取消订阅存储在附加属性中的集合的 CollectionChanged 事件
好的,我有一个附加属性(在静态类中声明),它将 INotifyCollectionChanged 属性附加到对象。
设置属性后,我想开始监视集合的更改,然后对集合所附加的对象执行一些操作。
第一次尝试:
private static void MyProperty_OnChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
// We need both the dependency object, and the collection args to process the notification
NotifyCollectionChangedEventHandler changedFunc = (sender, eventArgs) => MyProperty_OnCollectionChanged( d, sender, eventArgs );
if( e.OldValue != null )
e.OldValue.CollectionChanged -= changedFunc; // Can you see the bug?
if( e.NewValue != null )
e.NewValue.CollectionChanged += changedFunc;
}
为了将集合附加到处理程序中的对象,我将 d
拉入闭包。很容易,对吧?
好吧,我相信你能在这里看到这个错误。当集合被删除或替换为新集合时,它无法取消注册事件处理程序,因为changedFunc是具有不同闭包的新处理程序。
那么,这样做的正确方法是什么?
Ok, so I have an attached property (declared in a static class) which attaches an INotifyCollectionChanged
property to an object.
When the property is set, I want to start monitoring the collection for changes, and then perform some action on the object to which the collection is attached.
First attempt:
private static void MyProperty_OnChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
// We need both the dependency object, and the collection args to process the notification
NotifyCollectionChangedEventHandler changedFunc = (sender, eventArgs) => MyProperty_OnCollectionChanged( d, sender, eventArgs );
if( e.OldValue != null )
e.OldValue.CollectionChanged -= changedFunc; // Can you see the bug?
if( e.NewValue != null )
e.NewValue.CollectionChanged += changedFunc;
}
In order to get the object the collection is attached to into the handler, I pull d
into the closure. Easy enough, right?
Well, I'm sure you can see the bug here. When the collection is removed or replaced with a new collection, it fails to un-register the event handler, because changedFunc is a new handler with a different closure.
So, what's the right way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
从您的代码中,不清楚这个静态方法位于何处。
有什么方法可以将事件处理程序存储为其所属类的成员变量吗?这将是一个可以根据需要添加和删除的单一参考。当前,每次 MyProperty_OnChanged 触发时,您都会构建一个新的事件处理程序。
或者,您是否可以更改集合以存储对事件处理程序的引用,以便您可以通过 e.OldValue.OldHandler (或类似的)访问它,以便稍后可以访问它?
From your code, it's not clear where this static method lives.
Is there some way you can store the event handler as a member variable of the class it belongs to? That would be a singular reference that could be added and removed as necessary. You are currently constructing a new event handler each time MyProperty_OnChanged fires.
Alternately, can you change your collection to store a reference to the event handler such that you can access it through e.OldValue.OldHandler (or similar) so you would have access to it later?
我通过使用另一个附加属性来保存包含事件处理程序和对
d
的引用的私有对象来解决这个问题。实际上,我显式创建了一个闭包类,并保留对它的引用。但这对我来说似乎是一个相当严厉的方法,我真的在寻找一个更优雅的解决方案。
I solved this by using another attached property to hold a private object containing the event handler and reference to
d
. Effectively I'm explicitly creating a closure class, and keeping a reference to it.But this seems a pretty heavy handed approach to me, I was really looking for a more elegant solution.