The PropertyGrid control in the Extended WPF Toolkit was released in version 1.4.0 as beta.  Since then I have had another release of version 1.5.0 in which the PropertyGrid was still in beta.  Well it is beta no more! I have given the PropertyGrid a lot of love an affection over the past few weeks and it is finally ready for prime time.  Unfortunately, you will have to wait until the release of version 1.6.0 to get an official version.  Luckily for you, the source code is available for you to download and compile to get the latest and greatest PropertyGrid features.  So what can you do with the PropertyGrid?  Let’s look at some of the notable new and improved features.

propertygrid

Of course the PropertyGrid has the expected behavior of binding to an object instance and showing all the properties for your editing desires.  It allows you sort display properties by category or alphabetically.  It also provides a nice little search textbox so you can find exactly what you are looking for.

Specifying Properties

By default the PropertyGrid will autogenerate all the properties for a given object. Never fear, you can override this behavior by setting the AutoGenerateProperties property to False, and then provide a collection of PropertyDefinitions of the properties you would like to show.

specifyingproperties

<extToolkit:PropertyGrid x:Name="_propertyGrid" Width="450" Margin="10"
                         AutoGenerateProperties="False">
    <!– Only the following properties will be displayed in the PropertyGrid –>
    <extToolkit:PropertyGrid.PropertyDefinitions>
        <extToolkit:PropertyDefinition Name="FirstName" />
        <extToolkit:PropertyDefinition Name="FavoriteColor" />
        <extToolkit:PropertyDefinition Name="PetNames" />
    </extToolkit:PropertyGrid.PropertyDefinitions>
</extToolkit:PropertyGrid>

 

Custom Editors

By default the PropertyGrid comes with 14 built-in editors:

  • CheckBoxEditor
  • CollectionEditor
  • ColorEditor
  • DateTimeUpDownEditor
  • DecimalUpDownEditor
  • DoubleUpDownEditor
  • EnumComboBoxEditor
  • FontComboBoxEditor
  • IntegerUpDownEditor
  • ItemsSourceEditor
  • PrimitiveTypeCollectionEditor
  • TextBlockEditor
  • TextBoxEditor
  • TimeSpanEditor

These editors don’t meet your needs? No problem!  You can override the default editors with your own custom editors with a DataTemplate. Simply define an EditorDefinition that either targets a Type, property name, or both and set the EditorDefinition.EditorTemplate to an instance of a DataTemplate. Be sure to bind your custom editor to the bound property item’s Value property.

<extToolkit:PropertyGrid x:Name="_propertyGrid1" Width="450" Margin="10">
    <extToolkit:PropertyGrid.EditorDefinitions>
        
        <!– This EditorDefinition will provide a TextBox to any property that is of type HorizontalAlignment, replacing the default ComboBox editor. –>
        <extToolkit:EditorDefinition TargetType="{x:Type HorizontalAlignment}">
            <extToolkit:EditorDefinition.EditorTemplate>
                <DataTemplate>
                    <TextBox Background="Green" Text="{Binding Value}" /> <!– Always bind your editor's value to the bound property's Value –>
                </DataTemplate>
            </extToolkit:EditorDefinition.EditorTemplate>
        </extToolkit:EditorDefinition>
        
        <!– This EditorDefinition will provide a TextBlock to any property that has any of the defined property names, replacing the default editor. –>
        <extToolkit:EditorDefinition>
            <extToolkit:EditorDefinition.PropertiesDefinitions>
                <extToolkit:PropertyDefinition Name="Age" />
                <extToolkit:PropertyDefinition Name="WritingFont" />
                <extToolkit:PropertyDefinition Name="Spouse" />
            </extToolkit:EditorDefinition.PropertiesDefinitions>
            <extToolkit:EditorDefinition.EditorTemplate>
                <DataTemplate>
                    <TextBlock Background="Yellow" Text="{Binding Value}" />
                </DataTemplate>
            </extToolkit:EditorDefinition.EditorTemplate>
        </extToolkit:EditorDefinition>
        
        <!– This EditorDefinition will provide a TextBox to any property that is of type Boolean and that has any of the defined property names, replacing the default editor. –>
        <extToolkit:EditorDefinition TargetType="{x:Type sys:Boolean}">
            <extToolkit:EditorDefinition.PropertiesDefinitions>
                <extToolkit:PropertyDefinition Name="DateOfBirth" />
                <extToolkit:PropertyDefinition Name="LastName" />
            </extToolkit:EditorDefinition.PropertiesDefinitions>
            <extToolkit:EditorDefinition.EditorTemplate>
                <DataTemplate>
                    <TextBox Background="Red" Text="{Binding Value}" />
                </DataTemplate>
            </extToolkit:EditorDefinition.EditorTemplate>
        </extToolkit:EditorDefinition>
        
    </extToolkit:PropertyGrid.EditorDefinitions>
</extToolkit:PropertyGrid>

Don’t like DataTemplates? No problem!  You can supply editors for a property by using the System.ComponentModel.EditorAttribute. In order to provide an editor with an attribute, the editor MUST implement the ITypeEditor interface. Your editor can be a simple class or a complex UserControl.

customeditor_attributes

public class Person
{
    [Category("Information")]     [DisplayName("First Name")]     [Description("This property uses a TextBox as the default editor.")]     //This custom editor is a Class that implements the ITypeEditor interface
    [Editor(typeof(FirstNameEditor), typeof(FirstNameEditor))]     public string FirstName { get; set; }

    [Category("Information")]     [DisplayName("Last Name")]     [Description("This property uses a TextBox as the default editor.")]     //This custom editor is a UserControl that implements the ITypeEditor interface
    [Editor(typeof(LastNameUserControlEditor), typeof(LastNameUserControlEditor))]     public string LastName { get; set; }
}

Your editors can be created as a class:

//Custom editors that are used as attributes MUST implement the ITypeEditor interface.
public class FirstNameEditor : Microsoft.Windows.Controls.PropertyGrid.Editors.ITypeEditor
{
    public FrameworkElement ResolveEditor(Microsoft.Windows.Controls.PropertyGrid.PropertyItem propertyItem)
    {
        TextBox textBox = new TextBox();
        textBox.Background = new SolidColorBrush(Colors.Red);

        //create the binding from the bound property item to the editor
        var _binding = new Binding("Value"); //bind to the Value property of the PropertyItem
        _binding.Source = propertyItem;
        _binding.ValidatesOnExceptions = true;
        _binding.ValidatesOnDataErrors = true;
        _binding.Mode = propertyItem.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay;
        BindingOperations.SetBinding(textBox, TextBox.TextProperty, _binding);
        return textBox;
    }
}

Or as a complex UserControl:

<UserControl x:Class="Samples.Modules.PropertyGrid.LastNameUserControlEditor"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="_uc">
        <StackPanel>
            <TextBox Text="{Binding Value, ElementName=_uc}" Background="YellowGreen" />
            <Button Click="Button_Click">Clear</Button>
        </StackPanel>
</UserControl>

public partial class LastNameUserControlEditor : UserControl, ITypeEditor
{
    public LastNameUserControlEditor()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(LastNameUserControlEditor), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }        

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Value = string.Empty;
    }

    public FrameworkElement ResolveEditor(Microsoft.Windows.Controls.PropertyGrid.PropertyItem propertyItem)
    {
        Binding binding = new Binding("Value");
        binding.Source = propertyItem;
        binding.Mode = propertyItem.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay;
        BindingOperations.SetBinding(this, LastNameUserControlEditor.ValueProperty, binding);
        return this;
    }
}

Custom ItemsSource

Sometimes it is desirable to want to provide a collection of values represented by a ComboBox for a given property. The PropertyGrid supports this scenario by creating a class that implements the IItemsSource interface and decorating your property with the ItemsSourceAttribute.

custom_itemssource

public class Person
{
    [Category("Writing")]     [DisplayName("Writing Font Size")]     [Description("This property uses the DoubleUpDown as the default editor.")]     [ItemsSource(typeof(FontSizeItemsSource))]     public double WritingFontSize { get; set; }
}

public class FontSizeItemsSource : IItemsSource
{
    public IList<object> GetValues()
    {
        List<object> sizes = new List<object>()
        {
            5.0,5.5,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,12.0,14.0,16.0,18.0,20.0
        };
        return sizes;
    }
}

Expandable Properties

Wait a minute… I’m not done yet.  Do you have a property of a complex object that you want to expand in the PropertyGrid?  You do?  Well then you want to pay attention to this.  The PropertyGrid supports this scenario and allows you to drill down into a property’s heirarchy. To enable this behavior you must decorate your property with the ExpandableObject attribute.

expandableobject

public class Person
{
    [Category("Information")]     [DisplayName("First Name")]     [Description("This property uses a TextBox as the default editor.")]     public string FirstName { get; set; }

    [Category("Conections")]     [Description("This property is a complex property and has no default editor.")]     [ExpandableObject]     public Person Spouse { get; set; }
}

Conclusion

As you can see, I have put a lot of time and effort into this control to make it as feature rich and flexible as possible.  This WPF PropertyGrid is freely available in the Extended WPF Toolkit.  All I ask, is that if you use the Extended WPF Toolkit, can you please rate the project and leave feedback with your impressions.  It is always nice to receive feedback to know if my efforts are paying off. Enjoy!

Brian Lagunas

View all posts

9 comments

  • First off, thanks for releasing this Brian!
    It’s truly powerful, and seems great!
    I have a question for you though, consider a scenario where one would like to use your PropertyGrid, but you don’t have a backing data class for it at compile time, say for instance you would read a list of editable properties from a datasource somewhere. Would it be possible somehow? I tried with a dynamic ExpandoObject but to no avail.

  • So much coolness! Thanks.

    When will the property grid emerge from beta?

    Also,

    Is there a way to customize the text of the property grid’s title like you can customize the display names of fields? For instance, in your CustomAttributeEditorPerson example, you’ve customized the fields so they display with spaces, but the property grid’s title isn’t customized (“CustomAttributeEditorPerson” with no spaces).

  • Multiple comments because your work is very cool.

    I’m looking for a way to control enable/disable and visible/invisible states on individual properties, but not finding anything. Can you point me in the right direction?

    The motivation is that sometimes the value of one property makes another property inapplicable.

  • Hi,

    I’m wondering if commands can be placed in the PropertGrid (in the form of a button)?

    Thanks,
    A

Follow Me

Follow me on Twitter, subscribe to my YouTube channel, and watch me stream live on Twitch.