Binding to a collection of PropertyDefinitions

  • 4 minutes to read

When engineering a WPF application using the MVVM architectural pattern, you may be required to describe property and collection definitions in a Model or ViewModel. The PropertyGridControl can automatically retrieve settings for property and collection definitions from a Model or ViewModel.

View Model Implementation

Assume a View Model. It includes the following classes.

  • ViewModel - the View Model. The View Model exposes the EditObject that will be edited within the PropertyGrid, and a set of properties of the edit object (via the Properties property).
  • Employee - a data object that contains employee information (e.g., first and last names, job position, etc.).
  • Property - describes a property (or collection) definition at the View Model level. This class provides properties that correspond to property definition settings.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace WpfApplication1 {
    public class ViewModel {
        public ViewModel() {
            EditObject = new Employee() {
                FirstName = "John",
                LastName = "Smith",
                Position = "Senior Developer",
                BirthDate = new DateTime(1987, 12, 15),
                PreviousPositions = new Positions() { "Junior Developer", "Middle Developer" }
            };
            Properties = new ObservableCollection<Property>();
            Properties.Add(new Property() { Name = "FirstName" });
            Properties.Add(new Property() { Name = "LastName" });
            Properties.Add(new Property() { Name = "Position" });
            Properties.Add(new Property() { Name = "BirthDate" });
            Properties.Add(new Property() { CollectionName = "PreviousPositions" });
        }

        public Employee EditObject { get; set; }
        public ObservableCollection<Property> Properties { get; set; }
    }

    public class Property {
        public string CollectionName { get; set; }
        public string Name { get; set; }
    }

    public class Employee {
        public DateTime BirthDate { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Position { get; set; }
        public Positions PreviousPositions { get; set; }
    }

    public class Positions : List<string> {
    }
}
NOTE

If the Properties collection might be changed after it has been assigned to the PropertyGrid control, it should implement INotifyCollectionChanged, so that changes made within a View Model are automatically reflected by the property grid.

Property Definition Templates and Template Selector

The PropertyGridControl generates property (and collection) definitions based on property definition templates.

To choose the required template based on the property definition settings, use the template selector.

The code sample below demonstrates how to implement templates for property and collection definitions (see XAML: PropertyTemplate and CollectionTemplate) and how to implement a template selector (the PropertyDefinitionTemplateSelector class), that will select the required template for each property or collection definition.

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dxprg="http://schemas.devexpress.com/winfx/2008/xaml/propertygrid"
    xmlns:local="clr-namespace:WpfApplication1"
    Height="350"
    Width="525"
    Title="MainWindow">

    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>

    <Window.Resources>
        <local:PropertyDefinitionTemplateSelector x:Key="PropertyDefinitionTemplateSelector"/>
        <DataTemplate x:Key="PropertyTemplate">
            <dxprg:PropertyDefinition Path="{Binding Name}" />
        </DataTemplate>
        <DataTemplate x:Key="CollectionTemplate">
            <dxprg:CollectionDefinition Path="{Binding CollectionName}" />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <dxprg:PropertyGridControl Name="propertyGrid"
            PropertyDefinitionsSource="{Binding Properties}"
            PropertyDefinitionTemplateSelector="{StaticResource PropertyDefinitionTemplateSelector}"
            SelectedObject="{Binding EditObject}"
            ShowProperties="WithPropertyDefinitions" ExpandCategoriesWhenSelectedObjectChanged="True"/>
    </Grid>
</Window>
NOTE

If the PropertyGrid displays property definitions that can be described using a single template, you have no need to create a template selector. Instead, assign this template to the property grid's PropertyGridControl.PropertyDefinitionTemplate property.

Binding PropertyGrid to ViewModel

To bind the PropertyGridControl to a ViewModel, specify the following properties.

<Grid>
    <dxprg:PropertyGridControl Name="propertyGrid"
        PropertyDefinitionsSource="{Binding Properties}"
        PropertyDefinitionTemplateSelector="{StaticResource PropertyDefinitionTemplateSelector}"
        SelectedObject="{Binding EditObject}"
        ShowProperties="WithPropertyDefinitions" ExpandCategoriesWhenSelectedObjectChanged="True"/>
</Grid>

The image below illustrates the result.

property_grid_mvvm.png