C#:ObservableCollection - 为什么虚拟“CollectionChanged”事件?

时间:2013-05-31 13:29:39

标签: wpf observablecollection

为什么CollectionChanged事件在ObservableCollection虚拟?我们有虚拟OnCollectionChanged方法,它应该足以覆盖事件调用权限吗?

我没有看到任何这种用法,虚拟事件也是邪恶的。笨拙地使用虚拟事件会带来很多逻辑问题,但是即使在框架中也存在虚拟事件。

这只是糟糕的设计,还是有人在真实的单词中使用它?

2 个答案:

答案 0 :(得分:3)

我们可以讨论基类和设计,但这里不是直接/学术的答案,而是更多的例子。我个人觉得很好,我可以扩展ObservableCollection并覆盖OnCollectionChanged。 ObservableCollection非常繁琐,每次添加/删除项目时,它都会使用属性更改的消息轰炸UI线程并将其减慢(在数据网格中,例如,要更新的每个绑定)。因此,据我所知,许多人扩展了ObservableCollection来抑制此类通知,直到完成添加项目为止。仅仅因为WPF控制DataGrids / ListViews等..响应CollectionChanged这是有效的。

这是用法,我刷新我的数据,而不是一次添加一个项目,我填充List然后我只用它重置ObservableCollection一次,这极大地加快了UI响应速度:

private void OnExecuteRefreshCompleted(IEnumerable<MyObject> result)
{
UiUtilities.OnUi(() => { _myObservableCollectionField.Reset(result, true);              
        });

这是我的扩展课程:

public class ObservableCollectionExtended<T> : ObservableCollection<T>
{
    private bool _suppressNotification;

            //without virtual , I couldn't have done this override
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!_suppressNotification)
            base.OnCollectionChanged(e);
    }

    public void Clear(bool suppressNotificationUntillComplete)
    {
        _suppressNotification = suppressNotificationUntillComplete;

        Clear();

        _suppressNotification = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public void ClearItems(bool suppressNotificationUntillComplete)
    {
        _suppressNotification = suppressNotificationUntillComplete;

        base.ClearItems();

        _suppressNotification = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public void AddRange(IEnumerable<T> list, bool suppressNotificationUntillComplete)
    {
        if (list == null)
            throw new ArgumentNullException("list");

        _suppressNotification = suppressNotificationUntillComplete;

        foreach (T item in list)
            Add(item);

        _suppressNotification = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    /// <summary>
    /// clears old items, and new ones
    /// </summary>
    /// <param name="list"></param>
    /// <param name="suppressNotificationUntillComplete"></param>
    public void Reset(IEnumerable<T> list, bool suppressNotificationUntillComplete)
    {
        if (list == null)
            throw new ArgumentNullException("list");

        _suppressNotification = suppressNotificationUntillComplete;

        Clear();

        foreach (T item in list)
            Add(item);

        _suppressNotification = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

答案 1 :(得分:1)

我担心丹尼斯没有回答问题&#34;为什么CollectionChanged事件是虚拟的?&#34;而是问题&#34;为什么OnCollectionChanged()方法是虚拟的?&#34;。乔恩更恰当地回答了第一个问题。您可能对我之前做过的订阅者的不同处理感兴趣。 我们有两种不同的场景:

第一种情况: 我想提出CollectionChanged事件,并确保在此事件(委托列表)中调用的任何委托,在发生异常时不会中断调用以下委托。换句话说,事件由代表列表组成。如果我让10个订阅者(代表)和第3个代表提出异常,我可以继续调用其余的代理。标准实现中断调用。

第二种情况: 我可能希望让一些订阅者优先(他们更早地接收事件),即使他们比其他订阅者更晚订阅。在&#34;添加&#34;事件我可以在我的自定义代表列表中移动一些特定订阅者更低或更高,后者用于提升事件..