Increasing WPF ObservableCollection performance

I have removed the CollectionViewSource and the grouping and the items are copied over in 1/2 a second, but with the grouping on it can take up to a minute because virtualisation does not work with the grouping.

I will need to decide whether to use the CollectionViewSource


I couldn't resist answering this. I don't think you won't need this answer anymore, but maybe somebody else can use it.

Don't think too hard (do not approach this multithreaded (this will make things error-prone and unnecessary complicated. Only use threading for hard calculations/IO), all those different actiontypes will make it very difficult to buffer. The most annoying part is, that if you remove or add 10000 items your application (listboxes) will be very busy with handling the events raised by the ObservableCollection. The event already supports multiple items. So.....

You could buffer the items until it changes the action. So Add actions will be buffered and wil be raised as batch if the 'user' changes action or flushes it. Haven't test it, but you could do something like this:

// Written by JvanLangen
public class BufferedObservableCollection<T> : ObservableCollection<T>
{
    // the last action used
    public NotifyCollectionChangedAction? _lastAction = null;
    // the items to be buffered
    public List<T> _itemBuffer = new List<T>();

    // constructor registeres on the CollectionChanged
    public BufferedObservableCollection()
    {
        base.CollectionChanged += new NotifyCollectionChangedEventHandler(ObservableCollectionUpdate_CollectionChanged);
    }

    // When the collection changes, buffer the actions until the 'user' changes action or flushes it.
    // This will batch add and remove actions.
    private void ObservableCollectionUpdate_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // if we have a lastaction, check if it is changed and should be flush else only change the lastaction
        if (_lastAction.HasValue)
        {
            if (_lastAction != e.Action)
            {
                Flush();
                _lastAction = e.Action;
            }
        }
        else
            _lastAction = e.Action;

        _itemBuffer.AddRange(e.NewItems.Cast<T>());
    }

    // Raise the new event.
    protected void RaiseCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (this.CollectionChanged != null)
            CollectionChanged(sender, e);
    }

    // Don't forget to flush the list when your ready with your action or else the last actions will not be 'raised'
    public void Flush()
    {
        if (_lastAction.HasValue && (_itemBuffer.Count > 0))
        {
            RaiseCollectionChanged(this, new NotifyCollectionChangedEventArgs(_lastAction.Value, _itemBuffer));
            _itemBuffer.Clear();
            _lastAction = null;
        }
    }

    // new event
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
}

Have fun!, J3R03N