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?