【问题标题】:How to use batching, something like BeginUpdate/EndUpdate, when doing bulk change in ViewModel in MVVM?在 MVVM 中对 ViewModel 进行批量更改时,如何使用批处理(例如 BeginUpdate/EndUpdate)?
【发布时间】:2012-02-16 04:46:05
【问题描述】:

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

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

在某些情况下,我在 chartDataCollection 中添加了 100 个项目,这导致 CollectionChange 事件被触发 100 次,并且每次都呈现图表,这需要花费大量时间。

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

【问题讨论】:

    标签: c# .net wpf mvvm


    【解决方案1】:

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

    一种方法是实现您自己的 MyBatchObservableColleciton,派生或(更好地)嵌入 List(或任何其他适当的集合)。实现方法来修改内部集合并记录所有这些更改。当您准备好将所有更改提交到 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( );
        }
    
    }
    

    我自己从未尝试过,但我认为这是要走的路。 Google for Custom & ObservableCollection。虽然不准确,但很少有实现。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 这是一个错误的答案。除了 IEnumerable 之外,还必须实现 INotifyCollectionChanged
      • 不,它会起作用,只是您必须在每次添加/删除图表数据源时重置整个 ChartDataCollection 属性
      • @Uri INotifyCollectionChanged 提出了 OP 遇到的问题。虽然您的解决方案有效,但它是过度架构的。我的解决方案有效,而且更简单。
      【解决方案3】:

      为什么不对所有更改使用单独的集合,然后合并两个集合并在完成后将其分配给您的公共集合?这只会触发一次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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-10
        • 1970-01-01
        相关资源
        最近更新 更多