Delayable Notification Collection – WPF/Silverlight MVVM

By | December 8, 2012

In my last project (WPF/MVVM) I had to deal with a lot of data in the application. I stored the data in a ObservableCollection and bound the collection to a chart and a grid. Everything worked very well. But the data in the ObservableCollection changed frequently. By default, the ObservableCollection notifies every change in the collection. (Add,Remove etc.) This slowed down the application extremely, because I had to iterate through the collection and add or remove multiple items. Therefore, I decided to create a custom collection which delays the notification. The code below sends at the end only one “dummy” notification. It don’t tells what exactly happend with the data.

Here is the code:

public class DelayableNotificationCollection<T> : ObservableCollection<T>
{
    #region Types

    public class DelayHandler : IDisposable
    {
        public bool CanNotify { get; set; }
        public Func<bool> NotifyIfTrue { get; set; }

        private DelayableNotificationCollection<T> Collection;

        public DelayHandler(DelayableNotificationCollection<T> collection)
        {
            this.Collection = collection;
            this.CanNotify = true;
        }

        public void ForceNotify()
        {
            this.Collection.ExecBaseOnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        public void Notify()
        {
            // Dummy notification
            this.Collection.ExecBaseOnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        public void Dispose()
        {
            if (this.NotifyIfTrue != null)
            {
                if (this.NotifyIfTrue())
                    this.Notify();
            }
            else
                this.Notify();

            this.CanNotify = true;
            this.NotifyIfTrue = null;
        }
    }

    #endregion

    private DelayHandler Handler;

    public DelayableNotificationCollection()
    {
        this.Handler = new DelayHandler(this);
    }

    private void ExecBaseOnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnCollectionChanged(e);
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (this.Handler.CanNotify)
            this.ExecBaseOnCollectionChanged(e);
    }

    public DelayHandler Delay(Func<bool> notifyIfTrue = null)
    {
        this.Handler.CanNotify = false;
        this.Handler.NotifyIfTrue = notifyIfTrue;
        return this.Handler;
    }
}

The following example shows how to use the DelayableNotificationCollection class:

static void Main(string[] args)
{
    var collection = new DelayableNotificationCollection<string>();
    collection.CollectionChanged += collection_CollectionChanged;

    Console.WriteLine("> CollectionChanged will be raised.");
    collection.Add("A");
    Console.WriteLine("> CollectionChanged will be raised.");
    collection.Add("B");
    Console.WriteLine("> CollectionChanged will be raised.");
    collection.Add("C");

    Console.WriteLine();

    using (var handler = collection.Delay())
    {
        Console.WriteLine("> CollectionChanged WON'T be raised.");
        collection.Add("D");
        Console.WriteLine("> CollectionChanged WON'T be raised.");
        collection.Add("E");
        Console.WriteLine("> CollectionChanged WON'T be raised.");
        collection.Add("F");
        Console.WriteLine("> CollectionChanged WILL be raised.");
        handler.ForceNotify();
        collection.Add("G");
        Console.WriteLine("> CollectionChanged WON'T be raised.");
        collection.Add("H");
        Console.WriteLine("> CollectionChanged WON'T be raised.");
        collection.Add("I");

        Console.WriteLine("> CollectionChanged will be raised.");
    }

    Console.WriteLine("> CollectionChanged will be raised.");
    collection.Add("J");
    Console.WriteLine("> CollectionChanged will be raised.");
    collection.Add("K");

    Console.Read();
}

static void collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    Console.WriteLine(">> Notification received.");
}

And here is the output:
DelayableNotificationCollection Demo

Cheers! 😉