Digi21.WinUI.PropertyGrid
1.0.0
Prefix Reserved
dotnet add package Digi21.WinUI.PropertyGrid --version 1.0.0
NuGet\Install-Package Digi21.WinUI.PropertyGrid -Version 1.0.0
<PackageReference Include="Digi21.WinUI.PropertyGrid" Version="1.0.0" />
<PackageVersion Include="Digi21.WinUI.PropertyGrid" Version="1.0.0" />
<PackageReference Include="Digi21.WinUI.PropertyGrid" />
paket add Digi21.WinUI.PropertyGrid --version 1.0.0
#r "nuget: Digi21.WinUI.PropertyGrid, 1.0.0"
#:package Digi21.WinUI.PropertyGrid@1.0.0
#addin nuget:?package=Digi21.WinUI.PropertyGrid&version=1.0.0
#tool nuget:?package=Digi21.WinUI.PropertyGrid&version=1.0.0
<img src="https://raw.githubusercontent.com/digi21/PropertyGrid/main/assets/icon-256.png" width="96" alt="" />
Digi21.WinUI.PropertyGrid
A property grid for WinUI 3. Point it at an object and it lists the object's properties as editable rows: an editor chosen from each property's type, grouped into categories, labelled from the attributes already on your model, validated, and kept in step with the object as it changes.
<img src="https://raw.githubusercontent.com/digi21/PropertyGrid/main/assets/gallery.png" width="820" alt="The gallery, showing categories, editors and a nested object" />
Features
- Reflection. Give it an object, or a type, and the rows build themselves.
- An editor per type. Text, numbers, booleans, enumerations, flags, dates, times, durations,
colours, brushes and more — including the cases that are easy to get wrong, like
decimalandlongstaying away from a double-backed number box. - Paths, with a browse button that asks your application to open the dialog — it knows the filter, the starting folder and the window handle; a library does not.
- Dialogs for anything that needs one — lists, complex objects, your own types. The grid shows a
summary and a
…, raises an event, and stays out of the way. The button only appears if you are listening. - A resizable name column. One splitter drags it in every row at once, at every level of nesting.
- A resizable description pane. Drag the divider above it for more room, or double-click that divider to fit it to the text. Anything longer scrolls inside it.
- Categories that collapse, from
[Category]or[Display(GroupName)]. - The attributes you already have:
[Browsable],[Category],[Description],[DisplayName],[ReadOnly],[DefaultValue], and the DataAnnotations equivalents. - Validation from DataAnnotations, from validators you supply, and from the object's own
INotifyDataErrorInfo. - Nested objects, opened into indented child rows in the same list, with the columns still lined up and cycles in the graph refused rather than followed.
ObservableObjectand anything else that raisesINotifyPropertyChanged. Edit the object from elsewhere and the grid follows; the subscription is weak, so a transient inspector does not pin your view model's lifetime to it.- Replaceable everywhere. Every colour is a resource key, every editor is a
DataTemplateyou can redeclare, and every control has aDefault…Styleto derive from. - Searching and filtering, by text or by a predicate of your own.
Requirements
Windows App SDK 1.8 or later, .NET 8 or later. A package built against 1.8 works unchanged in an application on 2.x: the WinUI assembly identity is the same and its surface is a superset, and NuGet resolves the dependency to the highest version in the graph.
Installation
dotnet add package Digi21.WinUI.PropertyGrid
Quickstart
<Page
xmlns:pg="using:Digi21.WinUI.PropertyGrid">
<pg:PropertyGrid SelectedObject="{x:Bind Layer}" />
</Page>
That is the whole integration. The model needs nothing from the library:
public class Layer : ObservableObject
{
private string name = "Parcels";
private int opacity = 80;
[Category("Identity")]
[DisplayName("Layer name")]
[Description("What this layer is called in the legend.")]
[Required]
public string Name
{
get => name;
set => SetProperty(ref name, value);
}
[Category("Appearance")]
[Range(0, 100)]
[DefaultValue(80)]
public int Opacity
{
get => opacity;
set => SetProperty(ref opacity, value);
}
}
Arranging the rows
<pg:PropertyGrid
PropertySort="Categorized"
SelectedObject="{x:Bind Layer}"
ShowDescription="True"
ShowSearchBox="True" />
PropertySort is NoSort, Alphabetical, Categorized or CategorizedAlphabetical. FilterText
narrows the list to what matches, and Filter takes a predicate for anything text cannot express.
The description pane starts at DescriptionHeight and the user drags it from there, down to
MinimumDescriptionHeight and up to whatever leaves MinimumRowsHeight for the rows.
CanResizeDescription="False" takes the divider away for a grid that should keep the height you
gave it.
Nested objects
A property opens into indented child rows when it, or its type, says so:
[Expandable]
public ServerSettings Server { get; } = new();
Set ExpansionPolicy="Automatic" to offer it for every object with properties of its own, which
suits an inspector and does not suit a settings dialog.
Showing a type
<pg:PropertyGrid SelectedType="local:Layer" />
Every row is read-only: there is no object to read a value from. Useful for looking at the shape of a type rather than at an instance of it.
Reacting to edits
grid.PropertyValueChanging += (_, arguments) =>
{
if (arguments.Row.Name == nameof(Layer.Name) && IsTaken(arguments.NewValue))
{
arguments.Cancel = true;
arguments.ErrorMessage = "That name is already used.";
}
};
grid.PropertyValueChanged += (_, arguments) => document.MarkDirty();
NewValue on the changed event is what the setter actually kept, which is not always what was
typed: a property that clamps its input reports the clamped value.
Custom editors
<pg:PropertyGrid SelectedObject="{x:Bind Layer}">
<pg:PropertyGrid.EditorTemplates>
<pg:PropertyEditorTemplateMap>
<pg:PropertyEditorTemplate Key="Percent">
<DataTemplate>
<Slider Maximum="100" Minimum="0" Value="{Binding DoubleValue, Mode=TwoWay}" />
</DataTemplate>
</pg:PropertyEditorTemplate>
</pg:PropertyEditorTemplateMap>
</pg:PropertyGrid.EditorTemplates>
</pg:PropertyGrid>
[PropertyEditor("Percent")]
public int Opacity { get; set; }
To replace a whole category of editors rather than the one for a type, declare a DataTemplate
under the matching name from PropertyEditorKeys in your App.xaml — every boolean in the
application changes at once. See docs/editors.md.
Theming
Every brush the grid uses is an alias of a WinUI system brush, so it follows the accent colour, both themes and high contrast on its own. Redeclare a key to change one:
<SolidColorBrush x:Key="PropertyGridCategoryBackgroundBrush" Color="#20FFFFFF" />
See docs/theming.md for the full list, the metrics, and how to retemplate a control.
Other languages
Every word the grid shows is either a resource key you redeclare or a property on
PropertyGridStrings. docs/localisation.md
has the lot translated into Catalan, English, Basque, French, Galician, German, Italian, Portuguese
and Spanish.
Types you do not own
PropertyGridMetadata.Default
.For<Rect>()
.Property(rectangle => rectangle.X, property => property.DisplayName("Left").Category("Position"))
.Ignore(rectangle => rectangle.Height);
Or handle AutoGeneratingProperty per grid, or replace discovery entirely with an
IPropertyDescriptionProvider when the properties are not CLR properties at all. See
docs/metadata.md.
Not in this version
- Opening a struct into child rows: a child row would write to a copy and the edit would be silently lost. A struct shows its text form, and can be given a dialog editor instead.
- A ready-made dialog for editing a list. The grid shows how many there are and offers the button; what opens is up to you.
- Showing several objects at once (
SelectedObjects). IDictionary.
Sample
samples/PropertyGridGallery exercises every feature and is the fastest way to try one:
dotnet run --project samples/PropertyGridGallery
Contributing
Issues and pull requests are welcome — see CONTRIBUTING.md.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows10.0.19041 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows10.0.19041
- Microsoft.WindowsAppSDK (>= 1.8.251106002)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 37 | 8/14/2026 |