依赖属性的getter/setter未被调用

4

我正在尝试创建一个派生自标准表格(Grid)的自定义控件。我将ObservableCollection作为自定义控件的DependencyProperty添加进去。但是,它的get/set从来没有被访问到过。我能否得到一些关于如何创建一个正确使用ObservableCollection的DependencyProperty的指导?

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));

}

ObservableCollection 应该在你的 ViewModel 中,而不是你的控件中。 - thumbmunkeys
它已经在我的视图模型中了。但是,我该如何将其传递给网格?难道网格不应该知道如何处理集合吗? - phm
您可以将依赖属性定义为 IEnumerable,就像 ItemsControl.ItemsSource 一样。或者发布您的代码,以便其他人可以看到其中的问题所在。 - Clemens
我已经尝试使用IEnumerable,但也没有成功。 - phm
2
当您在XAML中设置此Items属性时,WPF将直接将值分配给基础依赖属性,而不调用您的属性setter。这也许就是为什么您注意到它没有被调用的原因? - Clemens
2个回答

10
我建议不要将ObservableCollection作为“Items”依赖属性的类型。
这里使用ObservableCollection的原因(我猜)是为了在分配属性值时使UserControl能够附加“CollectionChanged”处理程序。但是,ObservableCollection过于特定。
The approach used in WPF (for example, in ItemsControl.ItemsSource) is to define a basic interface type (such as IEnumerable) and, when the property is assigned a value, determine if the value collection implements certain more specific interfaces. At a minimum, this would include INotifyCollectionChanged, but the collection may also implement ICollectionView and INotifyPropertyChanged. None of these interfaces are mandatory, which allows your dependency property to bind to various types of collections, ranging from a simple array to a complex ItemCollection.
Your OnItemsChanged property change callback would then resemble the following:
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
}

4

WPF绑定机制可能会绕过标准CLR属性,直接访问依赖属性的访问器(GetValueSetValue)。

这就是为什么逻辑不应该放在CLR属性中,而应该放在一个更改处理程序中。

此外,ObservableCollection<string>永远不会被设置,因为当您从XAML使用集合属性时,如下所示:

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

其实它是在 Items 上调用了一个 get 方法,然后对每个元素调用了 Add 方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接