ObservableDictionary的替代品,专注于性能

时间:2012-09-10 18:23:33

标签: c# wpf performance

我正在处理的c#app使用了ObservableDictionary。这方面的表现不够快,无法满足其功能。 ObservableDictionary非常快速地与(删除,添加和更新元素)进行交互,并且必须在每次进行更改时进行排序。有没有我可以使用ObservableDictionary的替代方案,它将专注于性能并仍然能够快速排序?

1 个答案:

答案 0 :(得分:6)

编写自己的内容非常简单,每次添加/更新或删除都不会导致重新绑定。由于这个原因,我们写了自己的。基本上我们所做的是在处理集合中的所有对象之前禁用已进行更改的通知,然后生成通知。它看起来像这样。如您所见,我们使用MvvmLight作为我们的MVVM框架库。这将极大地提高性能。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using FS.Mes.Client.Mvvm.MvvmTools.MvvmLight;

namespace FS.Mes.Client.Mvvm.MvvmTools
{
    /// <summary>
    /// Our implementation of ObservableCollection. This fixes one significant limitation in the .NET Framework implementation. When items
    /// are added or removed from an observable collection, the OnCollectionChanged event is fired for each item. Depending on how the collection
    /// is bound, this can cause significant performance issues. This implementation gets around this by suppressing the notification until all
    /// items are added or removed. This implementation is also thread safe. Operations against this collection are always done on the thread that
    /// owns the collection.
    /// </summary>
    /// <typeparam name="T">Collection type</typeparam>
    public class FsObservableCollection<T> : ObservableCollection<T>
    {
        #region [Constructor]
        /// <summary>
        /// Constructor
        /// </summary>
        public FsObservableCollection()
        {
            DispatcherHelper.Initialize();
        }
        #endregion

        #region [Public Properties]
        /// <summary>
        /// Gets or sets a property that determines if we are delaying notifications on updates.
        /// </summary>
        public bool DelayOnCollectionChangedNotification { get; set; }
        #endregion

        /// <summary>
        /// Add a range of IEnumerable items to the observable collection and optionally delay notification until the operation is complete.
        /// </summary>
        /// <param name="items"></param>
        /// <param name="delayCollectionChangedNotification">Value indicating whether delay notification will be turned on/off</param>
        public void AddRange(IEnumerable<T> items, bool delayCollectionChangedNotification = true)
        {
            if (items == null)
                throw new ArgumentNullException("items");

            DoDispatchedAction(() =>
            {
                DelayOnCollectionChangedNotification = delayCollectionChangedNotification;

                // Do we have any items to add?
                if (items.Any())
                {
                    try
                    {
                        foreach (var item in items)
                            this.Add(item);
                    }
                    finally
                    {
                        // We're done. Turn delay notification off and call the OnCollectionChanged() method and tell it we had a 'dramatic' change
                        // in the collection.
                        DelayOnCollectionChangedNotification = false;
                        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                    }
                }
            });
        }

        /// <summary>
        /// Clear the items in the ObservableCollection and optionally delay notification until the operation is complete.
        /// </summary>
        public void ClearItems(bool delayCollectionChangedNotification = true)
        {
            // Do we have anything to remove?
            if (!this.Any())
                return;

            DoDispatchedAction(() =>
            {
                try
                {
                    DelayOnCollectionChangedNotification = delayCollectionChangedNotification;

                    this.Clear();
                }
                finally
                {
                    // We're done. Turn delay notification off and call the OnCollectionChanged() method and tell it we had a 'dramatic' change
                    // in the collection.
                    DelayOnCollectionChangedNotification = false;
                    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                }
            });
        }

        /// <summary>
        /// Override the virtual OnCollectionChanged() method on the ObservableCollection class.
        /// </summary>
        /// <param name="e">Event arguments</param>
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            DoDispatchedAction(() =>
            {
                if (!DelayOnCollectionChangedNotification)
                    base.OnCollectionChanged(e);
            });
        }

        /// <summary>
        /// Makes sure 'action' is executed on the thread that owns the object. Otherwise, things will go boom.
        /// </summary>
        ///<param name="action">The action which should be executed</param>
        private static void DoDispatchedAction(Action action)
        {
            DispatcherHelper.CheckInvokeOnUI(action);
        }
    }
}