4

Is there a way to pause the NotifyCollectionChanged event of an ObservableCollection? I thought something like the following:

public class PausibleObservableCollection<Message> : ObservableCollection<Message>
{
    public bool IsBindingPaused { get; set; }

    protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (!IsBindingPaused)
            base.OnCollectionChanged(e);
    }
}

This pauses the notification indeed, but obviously the then left out (but still added) items are within the NotifyCollectionChangedEventArgs and are therefore not passed to the bound DataGrid when I enable the notification again.

Will I have to come up with a custom implementation of a collection in order to control this aspect?

rdoubleui
  • 3,554
  • 4
  • 30
  • 51

2 Answers2

5

If you do not want to loose any notifications a temporary storage might work, the following might work but is untested:

public class PausibleObservableCollection<T> : ObservableCollection<T>
{
    private readonly Queue<NotifyCollectionChangedEventArgs> _notificationQueue
        = new Queue<NotifyCollectionChangedEventArgs>();

    private bool _isBindingPaused = false;
    public bool IsBindingPaused
    {
        get { return _isBindingPaused; }
        set
        {
            _isBindingPaused = value;
            if (value == false)
            {
                while (_notificationQueue.Count > 0)
                {
                    OnCollectionChanged(_notificationQueue.Dequeue());
                }
            }
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!IsBindingPaused)
            base.OnCollectionChanged(e);
        else
            _notificationQueue.Enqueue(e);
    }
}

This should push every change that happens while the collection is paused into a queue, which then is emptied once the collection is set to resume.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Looks like a promising and clear approach. I will try it and let you know how it works... – rdoubleui Mar 31 '11 at 18:34
  • Works nicely as suggested and I prefer this over thedugas' approach, as I will be having a couple thousand items in my DataGrid. Simple and working. – rdoubleui Apr 01 '11 at 14:40
1

To go along with @H.B's answer (I was testing while he/she posted) - you can pass the NotifyCollectionChangedAction.Reset Change Action as an event argument to the CollectionChanged event. Note that this will not be efficient on large collections.

public class PausibleObservableCollection<T> : ObservableCollection<T>
{
    private bool _isPaused = false;
    public bool IsPaused 
    { 
      get { return _isPaused; } 
      set 
      { 
          _isPaused = value;
          if (!value)
          { this.OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset)); }

      } 
    }

    protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (!IsPaused)
        { base.OnCollectionChanged(e); }
    }
}
dugas
  • 12,025
  • 3
  • 45
  • 51
  • I tried this, works as expected. However, I will be having a couple thousand items in my DataGrid. As I read, `NotifyCollectionChangedAction.Reset` basically tells the Grid to bind all items- so your hint concerning the perfomance is crucial. But good to know, that there's such an Option. – rdoubleui Apr 01 '11 at 14:44