我正在尝试创建一个从标准网格派生的自定义控件。 我添加了一个ObservableCollection作为Custom控件的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));
}
答案 0 :(得分:10)
我建议不要使用ObservableCollection作为Items
依赖项属性的类型。
在这里使用ObservableCollection的原因(我猜)是在分配属性值时允许UserControl附加CollectionChanged
处理程序。但是ObservableCollection太具体了。
WPF中的方法(例如在ItemsControl.ItemsSource中)是定义一个非常基本的接口类型(如IEnumerable
),并且在为属性分配值时,查明值集合是否实现了更多具体接口。这至少是INotifyCollectionChanged,但该集合也可能会实现ICollectionView和INotifyPropertyChanged。所有这些接口都不是强制性的,这将使您的依赖属性能够绑定到各种集合,从普通数组开始直到复杂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
}
答案 1 :(得分:4)
WPF绑定机制可能会绕过您的标准CLR属性并直接转到依赖项属性访问器(GetValue
和SetValue
)。
这就是为什么不应该将逻辑放在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
,然后为每个元素调用Add
。