I'm building a WPF application according to MVVM. I have an ObservableCollection in my ViewModel which is being used by a Datagrid. My app needs to check a remote resource for new additions and when these arrive, update the GUI and store the items in a database.
The way I'm doing this is I have a ServiceLayer that checks for new items, saves them to the db, and triggers an event. My UI subscribes to this event and updates the ObservableCollection.
The problem was as soon as new items arrived, the attempt to update the ObservableCollection triggered an error "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"
I did some reading and managed to fix this problem by adding a CollectionSynchronization lock
This works - but is it a good approach i.e. are there any obvious issues that it will cause?
In my ServiceLayer
public async void CheckForNewOffers_Tick(object sender, ElapsedEventArgs e)
{
var webOffers = await _webAccess.GetLatestOffers();
var newOffers = new Collection<Offer>();
//CheckIfOffersAreNew
foreach(Offer o in webOffers)
{
if(!_currentOffers.Any(co=>co.Id == o.Id))
{
_currentOffers.Add(o);
newOffers.Add(o);
}
}
//Any new offers - save them in DB and signal event
if(newOffers.Count>0)
{
_data.StoreNewOffers(newOffers);
OnReceivingNewOffers(newOffers);
}
}
public event EventHandler<ICollection<Offer>> ReceivedNewOffers;
protected virtual void OnReceivingNewOffers(ICollection<Offer> newOffers)
{
ReceivedNewOffers?.Invoke(this, newOffers);
}
}
And in my UI
_itemsLock = new object();
BindingOperations.EnableCollectionSynchronization(_currentOffers, _itemsLock);
public void HandleNewOffers(object sender, ICollection<Offer> newOffers)
{
lock (_itemsLock)
{
//Implement code to add newOffers to ObservableCollection
foreach (Offer no in newOffers)
{
if (!_currentOffers.Any(co => co.Id == no.Id))
{
_currentOffers.Add(MapOffer(no));
}
}
}
}