我有一个继承自ObservableCollection<T>
的类。在该课程中,我有一个方法可以在内部更改集合,并且我想要抑制CollectionChanged
个事件。
public class ContentBlockList : ObservableCollection<int> {
public void SomeMethod() {
var handlers = CollectionChanged.GetInvocationList();
foreach (NotifyCollectionChangedEventHandler handler in handlers) {
CollectionChanged -= handler;
}
// do stuff here
foreach (NotifyCollectionChangedEventHandler handler in handlers) {
CollectionChanged += handler;
}
}
}
直观地看起来这应该起作用,因为我从其包含的对象中访问事件。不幸的是,编译器说
事件&#39; ObservableCollection.CollectionChanged&#39;只可以 出现在+ =或 - =
的左侧
如果我覆盖CollectionChanged
和OnCollectionChanged()
,我可以让代码工作,基本上用我自己的副本替换.NET版本。然而,不得不做这样的事情让我怀疑,我忽略了为什么一开始这样做是个坏主意的原因。感谢您对此的任何想法。
答案 0 :(得分:1)
由于取消订阅和重新订阅某个活动是一个相对的(不是很痛苦,但我不知道有多少订阅者可能会这么慢)我会建议您考虑覆盖{{1基础OnCollectionChanged
的方法和OnPropertyChanged
方法。
所以有类似的东西:
ObservableCollection
这允许在内部更新时抑制引发的事件,但这样做的方式意味着您不必取消订阅并重新订阅事件。
当正常添加到此集合时(即使用public class ContentBlockList : ObservableCollection<int>
{
private bool internallyUpdating;
public void SomeMethod()
{
this.internallyUpdating = true;
// Do Stuff (Add to base collection)
this.internallyUpdating = false;
this.OnPropertyChanged(new PropertyChangedEventArgs(@"Count");
this.OnPropertyChanged(new PropertyChangedEventArgs(@"Item[]");
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if(this.internallyUpdating)
{
return;
}
base.OnCollectionChanged(e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if(this.internallyUpdating)
{
return;
}
base.OnPropertyChanged(e);
}
}
),您将直接调用基本事件。但是,当您尝试在内部更新时,您将在完成之前禁止这些事件。
我认为这在性能方面更有效,但也比你看到的更简洁。
在最后一个说明中,我还会说您提供的contentBlockList.Add(1)
是NotifyCollectionChangedEventAction
。您可能已经对集合做了很大的改动,并且要处理它,您将希望任何订阅者必须刷新它们在集合上的外观,无论是WPF视图中的控件还是使用该集合的其他类。 / p>
答案 1 :(得分:0)
更好地使用它:
public class ContentBlockList : ObservableCollection<int>
{
ContentBlockList()
{
this.CollectionChanged += ContentBlockList_CollectionChanged;
}
void ContentBlockList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
}
}
如果您维护代码,请尝试使用
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ContentBlockList pp = new ContentBlockList();
pp.CollectionChanged += pp_CollectionChanged;
pp.CollectionChanged += pp_CollectionChanged1;
pp.Add(11112);
pp.SomeMethod();
}
void pp_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
}
void pp_CollectionChanged1(object sender, NotifyCollectionChangedEventArgs e)
{
}
}
public class ContentBlockList : ObservableCollection<int>
{
public void SomeMethod()
{
var handlers = CollectionChanged.GetInvocationList();
foreach (NotifyCollectionChangedEventHandler handler in handlers)
{
CollectionChanged -= handler;
}
// do stuff here
foreach (NotifyCollectionChangedEventHandler handler in handlers)
{
CollectionChanged += handler;
}
}
public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
}
答案 2 :(得分:0)
据我所知,你需要中断CollectionChanged
的解雇才能默默地做一些工作。因此,您可以创建类似__FireCollectionChanged
的布尔字段,然后覆盖OnCollectionChanged()
来执行:
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (__FireCollectionChanged)
base.OnCollectionChanged(e);
}
然后您可以控制该布尔字段是否触发了事件。
回答实际问题:您不能直接使用调用列表,因为事件不是委托类型字段。对于订阅/取消订阅行为,基本上只有两种方法add
和remove
。底层委托字段是在幕后创建的,您通常不想使用它。