RefreshItems
is called from the constructor of the ViewModel and when the user wishes it (RefreshCommand
on button click).
Delete is also bound to a DeleteCommand
.
I want to refresh the items within a new thread because of some animations which aren't fluid otherwise.
So the binding does not happen on the thread of the dispatcher but the deletion does and the deletion throws an exception (see code).
(TPL (async/await) is no option since XP has to be supported.)
public void RefreshItems()
{
new Thread(new ThreadStart(() =>
{
IsRefreshing = true;
var items = _db.GetItems();
var itemsCollectionView = CollectionViewSource
.GetDefaultView(new ObservableCollection<ItemType>(items));
Items = itemsCollectionView;
IsRefreshing = false;
})).Start();
}
private void Delete(ItemType item)
{
_db.DeleteItem(item);
var items = (ObservableCollection<ItemType>)Items.SourceCollection;
// InnerException: NotSupportedException
// Message: This type of CollectionView does not support changes
// to its SourceCollection from a thread different from
// the Dispatcher thread.
items.Remove(item);
}
I find it works best to treat data-bound items as though they were part of the UI. So, nothing that is data-bound should be accessed from a background thread.
Ideally, your database access would be using something like EF6 which supports asynchronous methods. However, since you do not have an
async
database layer, you can use a "fake asynchronous" approach to push the (synchronous) database work onto a background thread:However, this does require your database layer to be thread-agnostic. If it's caching some db connection or something that is tied to a specific thread then this approach won't work.