This project has moved. For the latest updates, please go here.

PropertyGrid Collection Editor not firing PropertyValueChanged event?

May 2, 2014 at 4:39 PM
I have two different types of collections in the PropertyGrid. I have a List<string> and a List<CustomType>. When editing either, the PropertyValueChanged event is not being fired. How can I inspect the changed values of a property that is a Collection? Is this a bug or by design? Do I need to make a custom editor?

For instance, when using the List of my CustomType, the Collection Control is opened when I select the property in the grid. That control has a its own propertygrid. After editing one of the properties in that grid, such as a "Content" property, how do I perform validation after the user hits "OK" on the Collection Control?
Developer
May 5, 2014 at 8:35 PM
Hi,

Currently, the propertyGrid fires the PropertyValueChanged event when the value of a propertyItem is changed. That is, for a Boolean, when the "IsChecked" property is modified, for a TextBox, when the "Text" property is changed....For a Collection, the value of the propertyItem is the "ItemsSource" property. So unless the collection itself is removed or changed, the PropertyValueChanged event will not be fired.

In your case, when an item is added, removed or modified in this collection, the collection instance remains, so PropertyValueChanged is not fired. Issue https://wpftoolkit.codeplex.com/workitem/20977 has been created.
May 5, 2014 at 10:04 PM
Hi thanks for the reply. Is there any current workaround for this issue? The only idea I can think of is creating a custom editor that fires an event.
Developer
May 6, 2014 at 12:21 PM
Hi,

I haven't try with a custom editor. Maybe it could work, but I can't be 100% sure. For List<CustomType>, a CollectionEditor is currently used. I believe a custom editor would look like it. You can find it here : Xceed.Wpf.Toolkit/PropertyGrid/Implementation/Editors/CollectionEditor.cs.

This Editor will need to get notified of changes in the PropertyGrid of its CollectionControl. In v2.4, the CollectionControl gives access to its PropertyGrid through a new property. It will then need to push the event to the main propertyGrid so that someone can access it. Or someone should have access to this CustomEditor to get this event. Unless you have another idea ?

Currently, depending on the type of the propertyItem, the PropertyGrid will choose the correct editor here : Xceed.Wpf.Toolkit/PropertyGrid/Implementation/PropertyGridUtilities.cs, in method "CreateDefaultEditor". But you can use the EditorAttribute to set a custom editor for a specific property.
May 6, 2014 at 3:51 PM
Thanks for the info. I'll make sure to post back when I look into this.
Jun 10, 2014 at 3:56 PM
I have successfully implemented a workaround for this issue for the time being. I created a CustomCollectionEditor class that mimics the code from the CollectionEditor. This editor has a style very similar to that of the normal CollectionEditor. When the editor's button is clicked, the editor creates a CollectionControlDialog To this dialog, I added a loaded event handler.

Since the current versions of the toolkit do not have access to the PropertyGrid of the CollectionControlDialog, I added an extension method to get the PropertyGrid control. I get the grid using the VisualTreeHelper. The performance is not great, but this method is just a temporary stopgap until future versions of the toolkit add access to the PropertyGrid.
public static Xceed.Wpf.Toolkit.PropertyGrid.PropertyGrid GetPropertyGrid(this Xceed.Wpf.Toolkit.CollectionControlDialog dialog)
{
    return FindVisualChildren<Xceed.Wpf.Toolkit.PropertyGrid.PropertyGrid>(dialog).FirstOrDefault();
}

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}
After I get the PropertyGrid control, i hook up some event handlers as well as add some EditorTemplateDefinitions in code. After the CollectionControlDialog is closed, I call a MainWindow.Instance.PropertyChanged() method that also gets called by my MainWindow's PropertyGrid_PropertyValueChanged event handler. This way, I can handle changes from the child dialog and perform tasks like unsaved change notifications.

I shared my workaround for adding EditorTemplateDefinitions in code in this discussion: https://wpftoolkit.codeplex.com/discussions/545551
Marked as answer by yourbuddypal on 6/10/2014 at 8:56 AM