在MVVM中对ViewModel进行批量更改时,如何使用批处理,如BeginUpdate/EndUpdate

本文关键字:何使用 批处理 EndUpdate BeginUpdate ViewModel 中对 MVVM | 更新日期: 2023-09-27 18:24:41

在我使用MVVM的Silverlight应用程序中,我有一个图表(第三方ComponentOne),它绘制了大量数据,因此需要花费大量时间进行渲染。

我的ViewModel中有一个ObservableCollection(比如chartDataCollection),它绑定到图表的数据源。

在某些场景中,我在chartDataCollection中添加了100秒的项,这导致CollectionChange事件被触发100秒,并且每次都渲染图表,这需要花费大量时间。

在C#中,我是否可以将这些更新组合在一起,并在完成后只通知UI一次就像我们在Winforms世界中使用BeginUpdate和EndUpdate语句将数据添加到数据网格时所做的那样。

在MVVM中对ViewModel进行批量更改时,如何使用批处理,如BeginUpdate/EndUpdate

要实现的接口是INotifyCollectionChanged。此接口通过CollectionChanged事件与WPF绑定通信-此事件的参数(NotifyCollectionChangedEventArgs)可以报告已更改的项目批。

一种方法是实现自己的MyBatchObservableColleciton,派生或(更好地)嵌入List(或任何其他适当的集合)。实现修改innter集合并记录所有这些更改的方法。当您准备好将所有更改提交到WPF时,只需发送更改列表即可。以下是您可以做什么的子集示例(仅实现集合的"添加"功能):

class BatchObservableColleciton<T> : INotifyCollectionChanged, IEnumerable
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    private List<T> _list;
    private List<T> _addedItems;
    public BatchObservableColleciton( ) {
        _list = new List<T>( );
        _addedItems = new List<T>( );
    }
    
    public IEnumerator GetEnumerator( )
    {
        return _list.GetEnumerator( );
    }
    public void Add( T item )
    {
        _list.Add( item );
        _addedItems.Add( item );
    }
    public void Commit( ) {
        if( CollectionChanged != null ) {
            CollectionChanged( this, new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Add, _addedItems ) );
        }
        _addedItems.Clear( );
    }
}

我自己从来没有尝试过,但我认为这是一条路。谷歌自定义&ObservableCollection。虽然不完全准确,但很少有实现。

不要使用ObservableCollection,而是使用利用INotifyPropertyChanged模式的简单IEnumerable属性。

private IEnumerable _ChartDataCollection;
public IEnumerable ChartDataCollection
{
    get
    {
        return _ChartDataCollection;
    }
    set
    {
        if (_ChartDataCollection != value)
        {
            _ChartDataCollection = value;
            NotifyPropertyChanged("ChartDataCollection");
        }
    }
}

为什么不为所有更改使用一个单独的集合,然后合并这两个集合,并在完成后将其分配给您的公共集合?这将只触发PropertyChanged事件一次。

// Create a new List that contains objects from your Collection
var list = new List<SomeItem>(SomeCollection);
foreach(var item in newItems)
{
    // Add new items to list
}
// Reset collection w/ items from List
SomeCollection = new ObservableCollection<SomeItem>(list);