.NET Zone is brought to you in partnership with:

Jonathan creates software, mostly with C#, XAML, and HTML5/JS. He was awarded the Microsoft MVP in the "Client Application Development section in January 2011 Jon is a DZone MVB and is not an employee of DZone and has posted 23 posts at DZone. You can read more from them at their website. View Full User Profile

WPF 4.5 – Part 7 : Accessing Collections on non-UI Threads

08.14.2012
| 6141 views |
  • submit to reddit

weakEventHere is the seventh (OMG !) post on the WPF 4.5 new features. Collections are a part of every application and their management is probably the first thing you learn to deal with in WPF.

To begin, you put everything on the main(the UI one) thread and it works just fine. After a few times, you realize that it freezes the application UI and that the users usually don’t like it. Then you put the collections creation/feeding on another Thread to free the UI’s Thread and you realize that it is not possible because : “This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread”.

In this post we will discover that this is over with WPF 4.5 (and that you’ll love it) !

How do we do this in WPF 4.0?

Let’s say that you have an application which display people on a list. The loading of the full list is quite long because it requires the program to go to a database via a WCF services and then to come back with the information.

In WPF 4.0 you have two different solutions:

  1. Retrieve the data on the UI Thread and wait after every add for the UI Thread to update. I don’t personnaly like this solution because this is kind of a hack and the interface reactivness remains odd.
  2. Tell the user to wait, then retrieve the data on a secondary Thread. Pass the information to the UI Thread and it creates the list on it. This is usually what I do even if it degrades the code readability because it’s more complex to write.

Here is a an example of this second solution:

private void LoadUpPersonsClick(object sender, RoutedEventArgs e)
{
    Task.Factory
        //Retrieve the persons on another thread.
        .StartNew>(RetrieveTheCollection)
        .ContinueWith(t =>
        {
            foreach (var p in t.Result) _persons.Add(p);
        },
        //Continue on the UI Thread
        TaskScheduler.FromCurrentSynchronizationContext());
}
 
public List RetrieveTheCollection()
{
    List persons = new List();
    for (int i = 0; i < 10; i++)
    {
        persons.Add(new Person() { Name = "Person " + i, Age = 40 + i % 5 });
    }
    return persons;
}

How do we do this in WPF 4.5?

Life is really easier in WPF 4.5: all you have to do is to to enable the features via the EnableCollectionSynchronization method. For the record, I struggled a lot to find this method which is a static method of the BindingOperations class.

It takes two parameters: the collection on which access across multiple threads will be enabled and a object which will be used as a lock. Easy as this snippet:

//Creates the lock object somewhere
private static object _lock = new object();
 
...
 
//Enable the cross acces to this collection elsewhere
BindingOperations.EnableCollectionSynchronization(_persons, _lock);

There is one another overload which takes a CollectionSynchronizationCallback callback and a could-be-null context as additionnal parameters. With this one you could decide which synchronization mechanism to use instead of the default one which is the lock.

So as you can imagine, all the synchronisation work is done for you by the framework, and the code you will finally end-up writing will be something like that:

private void AccessTheCollectionFromANonUIThreadClick(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(EditTheCollection);
}
 
public void EditTheCollection()
{
    for (int i = 0; i < 10; i++)
    {
        _persons.Add(new Person() { Name = "Person " + i, Age = 20 + i % 5 });
    }
}

It is clearly more readable, easy to understand, and easier to write!

As usual, a full project can be found on my Dropbox folder after registration.

Thanks to the WPF team for this great new feature !

 

Published at DZone with permission of Jon Antoine, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)