2012-02-03 100 views
3

我想创建一个从标准网格派生的自定义控件。 我添加了一个ObservableCollection作为自定义控件的DependencyProperty。但是,它的获取/设置从未达到。我可以在创建与ObservableCollection一起正确使用的DependencyProperty方面有一些指导吗?DependencyProperty getter/setter未被调用

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

} 
+0

observablecollection应该在您的viewmodel中,而不是您的控件... – thumbmunkeys 2012-02-03 10:15:31

+0

它已经在我的viewmodel中。但是,我如何将它传递给网格?网格不应该知道如何处理集合吗? – phm 2012-02-03 10:18:07

+0

您可以将依赖项属性定义为IEnumerable,如[ItemsControl.ItemsSource](http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemssource.aspx)。或者发布你的代码,这样有人可能会发现它有什么问题。 – Clemens 2012-02-03 10:27:24

回答

8

我建议不使用的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 
} 
+0

太棒了,男人! :-) – zoidbeck 2012-02-03 15:12:41

4

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

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

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

它实际上是调用得到Items,然后调用Add每个元素:

另外,ObservableCollection<string>将永远不会被因为当你使用集合属性从XAML,像下面的设置。