DependencyProperty getter/setter not being called

China☆狼群 提交于 2019-12-17 02:33:12

问题


I am trying to create a Custom control derived from a standard Grid. I added a ObservableCollection as a DependencyProperty of the Custom control. However, the get/set of it is never reached. Can I have some guidelines in creating a DependencyProperty that works correctly with and ObservableCollection?

public class MyGrid : Grid
{
    public ObservableCollection<string> Items
    {
        get
        {
            return (ObservableCollection<string>)GetValue(ItemsProperty);
        }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }

public static  DependencyProperty ItemsProperty =
                DependencyProperty.Register("Items", typeof(ObservableCollection<string>), 
        typeof(MyGrid), new UIPropertyMetadata(null, OnItemsChanged));

}

回答1:


I would suggest not to use ObservableCollection as the type of an Items dependency property.

The reason for having an ObservableCollection here (I guess) is to enable the UserControl to attach a CollectionChanged handler when the property value is assigned. But ObservableCollection is too specific.

The approach in WPF (e.g. in ItemsControl.ItemsSource) is to define a very basic interface type (like IEnumerable) and when the property is assigned a value, find out if the value collection implements certain more specific interfaces. This would at least be INotifyCollectionChanged here, but the collection might also implement ICollectionView and INotifyPropertyChanged. All these interfaces wouldn't be mandatory and that would enable your dependency property to bind to all sorts of collections, starting with a plain array up to a complex ItemCollection.

Your OnItemsChanged property change callback would then look like this:

private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    MyGrid grid = obj as MyGrid;

    if (grid != null)
    {
        var oldCollectionChanged = e.OldValue as INotifyCollectionChanged;
        var newCollectionChanged = e.NewValue as INotifyCollectionChanged;

        if (oldCollectionChanged != null)
        {
            oldCollectionChanged.CollectionChanged -= grid.OnItemsCollectionChanged;
        }

        if (newCollectionChanged != null)
        {
            newCollectionChanged.CollectionChanged += grid.OnItemsCollectionChanged;

            // in addition to adding a CollectionChanged handler
            // any already existing collection elements should be processed here
        }
    }
}

private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // handle collection changes here
}



回答2:


The WPF binding mechanism may bypass your standard CLR property and go directly to the dependency property accessors (GetValue and SetValue).

That is why logic should not be placed inside of the CLR property, but instead inside a changed handler.

Also the ObservableCollection<string> will never be set because when you use collection properties from XAML, like the following:

<local:MyGrid>
    <local:MyGrid.Items>
        <sys:String>First Item</sys:String>
        <sys:String>Second Item</sys:String>
    </local:MyGrid.Items>
</local:MyGrid>

It is actually calling a get on Items and then calling Add for each of the elements.



来源:https://stackoverflow.com/questions/9126946/dependencyproperty-getter-setter-not-being-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!