我可以以某种方式暂时禁用WPF数据绑定更改吗?

时间:2012-05-13 14:27:19

标签: c# wpf data-binding mvvm

我有一个使用MVVM数据绑定的WPF应用程序。我正在向ObservableCollection<...>添加项目,其中很多都是。

现在我想知道每次我在集合中添加一个,是否会立即触发事件并导致不必要的开销?如果是这样,我可以以某种方式暂时禁用事件通知并在我的代码结束时手动触发一次,这样如果我添加10k项,它只会被触发一次,而不是10k次?

更新:我尝试过这门课程:

using System;
using System.Linq;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace MyProject
{

    /// <summary> 
    /// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    public class ObservableCollection<T> : System.Collections.ObjectModel.ObservableCollection<T>
    {

        /// <summary> 
        /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T). 
        /// </summary> 
        public void AddRange(IEnumerable<T> collection)
        {
            foreach (var i in collection) Items.Add(i);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
        }

        /// <summary> 
        /// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). 
        /// </summary> 
        public void RemoveRange(IEnumerable<T> collection)
        {
            foreach (var i in collection) Items.Remove(i);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, collection.ToList()));
        }

        /// <summary> 
        /// Clears the current collection and replaces it with the specified item. 
        /// </summary> 
        public void Replace(T item)
        {
            ReplaceRange(new T[] { item });
        }
        /// <summary> 
        /// Clears the current collection and replaces it with the specified collection. 
        /// </summary> 
        public void ReplaceRange(IEnumerable<T> collection)
        {
            List<T> old = new List<T>(Items);
            Items.Clear();
            foreach (var i in collection) Items.Add(i);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, collection.ToList()));
        }

        /// <summary> 
        /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class. 
        /// </summary> 
        public ObservableCollection() : base() { }

        /// <summary> 
        /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection. 
        /// </summary> 
        /// <param name="collection">collection: The collection from which the elements are copied.</param> 
        /// <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception> 
        public ObservableCollection(IEnumerable<T> collection) : base(collection) { }
    }
}

我现在收到此错误:

  

其他信息:不支持范围操作。

错误来自:

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));

4 个答案:

答案 0 :(得分:12)

一种非常快速简便的方法是在调用AddRange时子类化ObservableCollection并暂停通知。有关说明,请参阅following blog post

答案 1 :(得分:10)

ObservableCollection的这个扩展很容易解决问题。

它公开了一个公共SupressNotification属性,允许用户控制何时抑制CollectionChanged通知。

它不提供范围插入/删除,但如果抑制了CollectionChanged通知,则在大多数情况下需要对集合执行范围操作。

此实现使用重置通知替换所有已抑制的通知。这在逻辑上是合理的。当用户禁止通知,进行批量更改然后重新启用通知时,应该发送重新发送通知。

public class ObservableCollectionEx<T> : ObservableCollection<T>
{
    private bool _notificationSupressed = false;
    private bool _supressNotification = false;
    public bool SupressNotification
    {
        get
        {
            return _supressNotification;
        }
        set
        {
            _supressNotification = value;
            if (_supressNotification == false && _notificationSupressed)
            {
                this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                _notificationSupressed = false;
            }
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (SupressNotification)
        {
            _notificationSupressed = true;
            return;
        }
        base.OnCollectionChanged(e);
    }
}

答案 2 :(得分:8)

有一种&#34;棘手的&#34;方式,但在我看来,相当准确,实现这一目标。 是写自己的ObservableCollection并实施AddRange处理。

通过这种方式,您可以将所有10k元素添加到某些&#34; holder集合中#34;之后,有一次你完成后,使用你的 AddRange的{​​{1}}来做到这一点。

有关此内容的更多信息,请访问此链接:

ObservableCollection Doesn't support AddRange method....

或者这个

AddRange and ObservableCollection

答案 3 :(得分:0)

很抱歉,我想发布此评论作为评论,因为我不会提供完整的实施细节,但它有点太长了。

关于不支持&#34;范围操作&#34;,这来自WPF用于绑定的ListCollectionView,它确实不支持范围操作。但是,正常CollectionView会这样做。

当绑定集合实现非通用ListCollectionView接口时,WPF选择使用IList。所以基本上要让AddRange解决方案正常工作,你需要完全重新实现ObservableCollection(而不是插入它),但没有非通用接口:

public class MyObservableCollection<T> :
    IList<T>,
    IReadOnlyList<T>,
    INotifyCollectionChanged,
    INotifyPropertyChanged
{
   // ...
}

在dotPeek或同等工具的帮助下,实现这一点并不需要很长时间。请注意,您可能会因为使用CollectionView而不是ListCollectionView而失去一些优化,但根据我自己的经验,全球使用此类可以完全改善效果。