【问题标题】:DependencyProperty getter/setter not being calledDependencyProperty getter/setter 未被调用
【发布时间】:2012-02-25 23:17:12
【问题描述】:

我正在尝试创建一个从标准网格派生的自定义控件。 我添加了一个 ObservableCollection 作为自定义控件的 DependencyProperty。但是,永远无法达到它的获取/设置。在创建与 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 应该在您的视图模型中,而不是您的控制中...
  • 它已经在我的视图模型中了。但是,我如何将它传递给网格?网格不应该也知道如何处理集合吗?
  • 您可以将依赖属性定义为 IEnumerable,就像 ItemsControl.ItemsSource 所做的那样。或者发布您的代码,以便有人可以看到它有什么问题。
  • 我已经用 IEnumerable 试过了,但也没有用。
  • 当您在 XAML 中设置此 Items 属性时,WPF 会将值直接分配给基础依赖项属性,而不是调用您的属性设置器。这也许就是您注意到它没有被调用的原因?

标签: wpf grid dependency-properties


【解决方案1】:

我建议不要使用 ObservableCollection 作为 Items 依赖属性的类型。

这里有一个 ObservableCollection 的原因(我猜)是为了让 UserControl 在分配属性值时附加一个CollectionChanged 处理程序。但是 ObservableCollection 太具体了。

WPF(例如ItemsControl.ItemsSource)中的方法是定义一个非常基本的接口类型(例如IEnumerable),当属性被赋值时,找出值集合是否实现了某些更具体的接口。这里至少是INotifyCollectionChanged,但集合也可能实现ICollectionViewINotifyPropertyChanged。所有这些接口都不是强制性的,这将使您的依赖属性能够绑定到各种集合,从普通数组开始到复杂的 ItemCollection

您的OnItemsChanged 属性更改回调将如下所示:

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】:

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

    这就是为什么不应该将逻辑放在 CLR 属性内,而应放在更改后的处理程序内的原因。

    此外,ObservableCollection&lt;string&gt; 也永远不会设置,因为当您使用 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多