C# WPF Attached属性无法为集合指定已更改的回调
编辑: 为了消除Instant closing作为重复项的所有混淆。请参见第(3)点,解释接受答案不适用的原因。简而言之,只要不使用XAML设置值,链接的答案就可以了,因为XAML将永远不会调用C# WPF Attached属性无法为集合指定已更改的回调,c#,wpf,xaml,attached-properties,C#,Wpf,Xaml,Attached Properties,编辑: 为了消除Instant closing作为重复项的所有混淆。请参见第(3)点,解释接受答案不适用的原因。简而言之,只要不使用XAML设置值,链接的答案就可以了,因为XAML将永远不会调用PropertyChangedCallback,因为它重新使用默认实例 问题: 考虑到带有XAML定义值的ObservableCollection类型的简单WPF附加属性: // public static class MyCollectionExetension.cs public static Ob
PropertyChangedCallback
,因为它重新使用默认实例
问题:
考虑到带有XAML定义值的
ObservableCollection
类型的简单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>
//公共静态类MyCollectionExetension.cs
公共静态ObservableCollection GetMyCollection(DependencyObject obj)
{
返回(ObservableCollection)对象GetValue(MyCollectionProperty);
}
公共静态void SetMyCollection(DependencyObject对象,ObservableCollection值)
{
对象SetValue(MyCollectionProperty,value);
}
公共静态只读DependencyProperty MyCollectionProperty=
DependencyProperty.RegisterAttached(“MyCollection”,类型为(ObservableCollection),
typeof(MyCollectionExetension),新属性元数据(null);
public static void DoThisWhenMyCollectionChanged(DependencyObjCT受让人,IEnumerable newValue){
//我如何调用这个?
}
//UserControl.xaml
1.
2.
我怎样才能钩住集合更改事件,同时访问它所附加的DependencyObject
和新项目?MyCollection必须在XAML中定义。一开始似乎很简单,但以下几点对我都不起作用:
新UIPropertyMetadata(null,CollectionChanged)
导致崩溃:newUIPropertyMetadata(newObservableCollection(),CollectionChanged)
但是,这会阻止CollectionChanged
由于XAML没有实例化新集合,而是向现有集合添加项而触发CollectionChanged
,同时提供新的UIPropertyMetadata(ProvideWithRegisteredCollectionChanged(),CollectionChanged)也不起作用,因为无法将DependencyProperty
传递给ProvideWithRegisteredCollectionChanged()
方法,因为处于静态上下文中MyCollection
中合并GetMyCollection()
getter或improverevaluecallback
都不能防止第1点的崩溃。因为在首次访问属性之前似乎没有调用它无法为集合类型附加的属性正确分配非null默认值。因此,必须在XAML中创建实例 由于直接在XAML中声明ObservableCollection似乎不太容易,请声明适当的派生类型:
public class MyCollection : ObservableCollection<int>
{
}
还要看一看:这无关紧要。重点是您必须在PropertyChangedCallback中附加CollectionChanged事件处理程序。这与dependency属性与attached属性无关。
CollectionChanged
回调(DependencyPropertyChangedCallback
)仅当dependency属性获得分配的新集合时才会调用。在CollectionChanged
回调中,您还必须订阅MyCollection.CollectionChanged
事件才能在实际集合(而不仅仅是属性)发生时收到通知已更改。@Clemens抱歉,我的错误,但答案仍然不适用,请参见编辑-如果您在XAML中设置值,它将重新使用默认值,而不是实例化新的ObservaleCollection
,因此将不会首先调用属性ChangedCallback
(并且答案只调用一次),我将永远不会给我机会注册NotifyCollectionChanged
。或者,如果您仍然不信任我,则答案确实适用,请尝试提供的示例并应用答案(我尝试的第3点).Afaik无法安全地为集合类型附加的属性提供非空的默认值。您必须在XAML中执行显式集合实例创建:…elements…
<Grid>
<b:MyCollectionExtension.MyCollection>
<b:MyCollection>
<sys:Int32>1</sys:Int32>
<sys:Int32>2</sys:Int32>
</b:MyCollection>
</b:MyCollectionExtension.MyCollection>
</Grid>
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)
{
// ...
}
}
}