System.InvalidOperationException with BindingOperations.EnableCollectionSynchronization in wpf

Viewed 120

We have an AsyncObservableCollection class which is inheriting from ObservableCollection in our wpf application. This class is having :

public Dispatcher Dispatcher
{
   get
   {
       if (_dispatcher == null)
       {
           if (Application.Current != null)
           {
               _dispatcher = Application.Current.Dispatcher;
           }
           else
           {
               _dispatcher = Dispatcher.CurrentDispatcher;
           }
       }
       return _dispatcher;
   }
   set
   {
       _dispatcher = value;
   }
}

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
   if (!Dispatcher.CheckAccess())
   {
       Dispatcher.BeginInvoke(
           new Action<NotifyCollectionChangedEventArgs>(OnCollectionChanged), e);
       return;
   }
   base.OnCollectionChanged(e);
}


protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
   if (!Dispatcher.CheckAccess())
   {
       Dispatcher.BeginInvoke(new Action<PropertyChangedEventArgs>(OnPropertyChanged), e);
       return;
   }

   base.OnPropertyChanged(e);
}

and there is another class RangeObservableCollection which is inheriting from this AsyncObservableCollectionClass, having only this inside it

private bool _suppressNotification;

public void ReplaceRange(IEnumerable<T> list)
{
    _suppressNotification = true;
    Clear();
    if (list != null)
    {
        foreach (T item in list)
        {
            Add(item);
        }
    }
    _suppressNotification = false;
    OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}



protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    if (!_suppressNotification)
    {
        base.OnCollectionChanged(e);
    }
}

now I tried to use BindingOperations.EnableCollectionSynchronization. Then inside our ListViewModelBase.cs created a lock object like this

private readonly static object _storiesCollectionLock = new object();

and inside the constructor of our ListViewModelBase we are creating the RangeObservableCollection and binding BindingOperations.CollectionRegistering

protected ListViewModelBase()
{
    _storiesCollection = new RangeObservableCollection<StoryInfoViewModel>();
    BindingOperations.CollectionRegistering += BindingOperations_CollectionRegistering;
}

private void BindingOperations_CollectionRegistering(object sender, CollectionRegisteringEventArgs e)
{
    if (e.Collection == _storiesCollection)
    {
        Dispatcher.BeginInvoke(new Action(() =>
        {
            BindingOperations.EnableCollectionSynchronization(_storiesCollection, _storiesCollectionLock);
        }));
    }
}

Then wherever in our project we are using this _storiesCollection, I am wrapping it in a lock which is using this _storiesCollectionLock object. Locking even the ListCollectionView which is getting populated with this observable collection. Have created properties in the ListViewModelBase, for the _storiesCollection and the _storiesCollectionLock object.

public RangeObservableCollection<StoryInfoViewModel> StoriesCollection
{
    get
    {
        lock (StoriesCollectionLock())
        {
            return _storiesCollection;
        }
    }
}

public static object StoriesCollectionLock()
{
    return _storiesCollectionLock;
}

Then in a separate StoryListViewModel inside my add method when i am trying to insert in this StoriesCollection on a worker thread

lock (StoriesCollectionLock())
{
   StoriesCollection.Insert(0, storyVM);
}

I am getting exceptions inside OnCollectionChanged in AsyncObservableCollection class

System.InvalidOperationException: 'Added item does not appear at given index '0'.'

also getting exception Message = "Cannot change ObservableCollection during a CollectionChanged event.", below is the stack trace for this

at System.Collections.ObjectModel.ObservableCollection1.CheckReentrancy() at System.Collections.ObjectModel.ObservableCollection1.InsertItem(Int32 index, T item) at System.Collections.ObjectModel.Collection`1.Insert(Int32 index, T item)

and

System.InvalidOperationException: ''1510' index in collection change event is not valid for collection of size '1500'.'

Can someone please help, what am i doing wrong or missing here? Or is it a known issue with EnableCollectionSynchronization?

0 Answers
Related