使用继承事件的调用列表是个坏主意吗?

时间:2016-03-14 17:45:38

标签: c# events observablecollection

我有一个继承自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;只可以   出现在+ =或 - =

的左侧

如果我覆盖CollectionChangedOnCollectionChanged(),我可以让代码工作,基本上用我自己的副本替换.NET版本。然而,不得不做这样的事情让我怀疑,我忽略了为什么一开始这样做是个坏主意的原因。感谢您对此的任何想法。

3 个答案:

答案 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);
}

然后您可以控制该布尔字段是否触发了事件。

回答实际问题:您不能直接使用调用列表,因为事件不是委托类型字段。对于订阅/取消订阅行为,基本上只有两种方法addremove。底层委托字段是在幕后创建的,您通常不想使用它。