编辑:
为了消除所有因即时关闭而造成的混乱。请参阅第(3.)点,解释为什么不接受接受的答案。简而言之,只要您不使用XAML设置值,链接的答案就可以了,因为XAML将从不调用PropertyChangedCallback
,因为它重复使用了默认实例。
问题:
考虑具有XAML定义值的ObservableCollection<T>
类型的简单WPF的附加属性:
// public static class MyCollectionExetension.cs
public static ObservableCollection<int> GetMyCollection(DependencyObject obj)
{
return (ObservableCollection<int>)obj.GetValue(MyCollectionProperty);
}
public static void SetMyCollection(DependencyObject obj, ObservableCollection<int> value)
{
obj.SetValue(MyCollectionProperty, value);
}
public static readonly DependencyProperty MyCollectionProperty =
DependencyProperty.RegisterAttached("MyCollection", typeof(ObservableCollection<int>),
typeof(MyCollectionExetension), new PropertyMetadata(null);
public static void DoThisWhenMyCollectionChanged(DependencyObejct assignee, IEnumerable<int> newValues) {
// how can I invoke this?
}
//UserControl.xaml
<Grid xmlns:sys="clr-namespace:System;assembly=mscorlib">
<b:DataGridExtensions.MyCollection >
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
</b:DataGridExtensions.MyCollection>
</Grid>
如何通过同时访问其附加的DependencyObject
和新项目来挂钩更改集合的事件? MyCollection 必须必须在XAML中定义。
乍一看似乎很简单,但以下任何一项对我都不起作用:
new UIPropertyMetadata(null, CollectionChanged)
会导致崩溃:XamlObjectWriterException:'集合属性'System.Windows.Controls.Grid'。'MyCollection'为空。'
好的,让我们提供默认值以避免上面的崩溃:new UIPropertyMetadata(new ObservableCollection<int>(), CollectionChanged)
但这会阻止CollectionChanged
触发,因为XAML不会实例化新集合,而是将项目添加到现有集合中。
修复以上问题并提供默认值CollectionChanged
的同时钩住new UIPropertyMetadata(ProvideWithRegisteredCollectionChanged(), CollectionChanged)
也不起作用,原因是由于无法将DependencyProperty
传递给ProvideWithRegisteredCollectionChanged()
方法处于静态环境中。
MyCollection
的getter或GetMyCollection()
中的CoerceValueCallback
中进行联合销售并不能阻止上述第1点的崩溃,因为在首次访问属性之前似乎没有调用它。答案 0 :(得分:1)
您不能为集合类型附加属性正确分配一个非空的默认值。因此,您必须在XAML中创建一个实例。
由于在XAML中直接声明ObservableCollection似乎不太容易,因此请声明适当的派生类型:
public class MyCollection : ObservableCollection<int>
{
}
并在XAML中创建一个实例,如下所示:
<Grid>
<b:MyCollectionExtension.MyCollection>
<b:MyCollection>
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
</b:MyCollection>
</b:MyCollectionExtension.MyCollection>
</Grid>
附加的属性声明应如下图所示,包括附加和分离CollectionChanged
事件处理程序的代码。
public static class MyCollectionExtension
{
public static MyCollection GetMyCollection(DependencyObject obj)
{
return (MyCollection)obj.GetValue(MyCollectionProperty);
}
public static void SetMyCollection(DependencyObject obj, MyCollection value)
{
obj.SetValue(MyCollectionProperty, value);
}
public static readonly DependencyProperty MyCollectionProperty =
DependencyProperty.RegisterAttached(
"MyCollection",
typeof(MyCollection),
typeof(MyCollectionExtension),
new PropertyMetadata(MyCollectionPropertyChanged));
public static void MyCollectionPropertyChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var oldCollection = e.OldValue as MyCollection;
var newCollection = e.NewValue as MyCollection;
if (oldCollection != null)
{
oldCollection.CollectionChanged -= MyCollectionChanged;
}
if (newCollection != null)
{
newCollection.CollectionChanged += MyCollectionChanged;
}
}
public static void MyCollectionChanged(
object o, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
// ...
}
}
}