3

为什么 CollectionChanged 事件是虚拟ObservableCollection?我们有虚拟OnCollectionChanged方法,应该足以覆盖事件调用吧?

我看不出有什么用处,而且虚拟事件也是邪恶的。虚拟事件的笨拙使用会带来很多逻辑问题,但是虚拟事件即使在框架中也存在。

这只是糟糕的设计还是有人在现实中使用它?

4

2 回答 2

4

我们可以就基类和设计进行辩论,但这不是直接/学术的答案,而是更多的示例。我个人觉得可以扩展 ObservableCollection 并覆盖 OnCollectionChanged 非常棒。ObservableCollection 非常健谈,每次添加/删除项目时,它都会用属性更改消息轰炸 UI 线程并减慢它的速度(例如,在数据网格中,要更新的每个绑定)。因此,据我所知,许多人扩展 ObservableCollection 以抑制此类通知,直到他们完成添加项目。仅仅因为 WPF 控制 DataGrids/ListViews 等。响应 CollectionChanged 这工作。

这是用法,我刷新我的数据,而不是一次添加一个项目,而是填充一个列表,然后我只用它重置 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));
    }
}
于 2013-05-31T13:53:52.647 回答
1

恐怕丹尼斯没有回答“为什么 CollectionChanged 事件是虚拟的?”这个问题。而是问题“为什么 OnCollectionChanged() 方法是虚拟的?”。乔恩回答了第一个问题更恰当。您可能对像我前段时间那样处理订阅者的不同方式感兴趣。让我们有两个不同的场景:

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

第二种情况:我可能想让一些订阅者被优先考虑(他们更早收到事件),即使他们比其他订阅者晚。在“添加”事件中,我可以在我的自定义委托列表中将一些特定的订阅者移动到更低或更高的位置,稍后用于引发事件。

于 2014-04-22T14:00:53.000 回答