I've been trying to figure out how to do this for a couple of days now.
It's a fairly common problem so I'll explain the situation as generically as possible so maybe others can get a bit of use out of it.
I have a list view on my WPF (using MVVM) dialog, it's bound to an observable collection of items with, say, five properties which are displayed in seperate columns.
I call a function which iterates over all the items and changes one of their properties. This function takes a while to get through all the items so I want it to update each item as it goes.
What are the options to do this so the UI remains responsive, and which is the simplest to implement?
If you are using C# 4.0, use
Task.Factory.StartNew(new Action(() =>
{
.....
//CALL YOUR UPDATE METHOD
})).ContinueWith( { //something to execute after, if need}..)
and when set ModelView object from other thread, use
Application.Current.Dispatcher.Invoke(new Action(() =>
{
//set ModelView object properties here
}));
I would use an ObservableCollection Extender that allows you to update the collection in another thread. This is what I use in my applications when dealing with collections:
public class ObservableCollectionExtender<T> : ObservableCollection<T>
{
/// <summary>
/// Source: New Things I Learned
/// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
/// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
/// Note: Improved for clarity and the following of proper coding standards.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// Use BlockReentrancy
using (BlockReentrancy())
{
var eventHandler = CollectionChanged;
// Only proceed if handler exists.
if (eventHandler != null)
{
Delegate[] delegates = eventHandler.GetInvocationList();
// Walk thru invocation list
foreach (NotifyCollectionChangedEventHandler handler in delegates)
{
var currentDispatcher = handler.Target as DispatcherObject;
// If the subscriber is a DispatcherObject and different thread
if ((currentDispatcher != null) &&
(currentDispatcher.CheckAccess() == false))
{
// Invoke handler in the target dispatcher's thread
currentDispatcher.Dispatcher.Invoke(
DispatcherPriority.DataBind, handler, this, e);
}
else
{
handler(this, e);
}
}
}
}
}
/// <summary>
/// Overridden NotifyCollectionChangedEventHandler event.
/// </summary>
public override event NotifyCollectionChangedEventHandler CollectionChanged;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With