WPF Listbox: non blocking UI… in simple steps

I have been working in a new project for the last 2 months…. a new feature of a WPF application. I am new to this world, but I realized has been a good experience… taking advantage of the MVVM pattern. In this post I want to share a small ‘dissertation’ how to write UI in real-time with a collection of objects that will update their state in real-time while some computation on them is done in others long-time consuming threads…

The key works here are: backgroundworker, viewmodel, dispatcher and thread safe collection…

Ingredients

The first ingredient is a class to implement the INotifyPropertyChanged; each property bound to the UI will expose a setter where invoke the PropertyChanged event of the inteface

The approach can be summarized:

  1. Define a class MainViewModel : INotifyPropertyChanged
    1. The ViewModel represents an abstraction of the actual xaml page, each property of the class is bound to the xaml through some Binding statement
      • Ex: <TextBlock Text=”{Binding ChangingText}”/>
      • The class has a property ChangingText that rises the PropertyChanged event each time is changed (by some thread), so the UI is notified of the new value of the property and will update itself… note that the class doesn’t call any method like we used to: TextBlockID.Text = ChangingText… if you do in this way your are not taking advantage of the Binding mechanics that will do the dirty job for you.
    2. Define a collection of SafeObservableCollection of what you want to bind to listbox, tabcontrol etc that will be updated by a long running process.
      • We can present the updated data in the UI without doing any check… only one time we bound the collection to the UI (xaml) then the Binding will notify the Ui of the changes (some logic of the INotifyPropertyChanged)
      • It’s not enough to use an ObservableColection, if you try you’ll ge this exception:
        • This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
    3. Use the BackgroundWorker to run the task (that usually requires long time) in async fashion to free the UI from any block
      • Using the SafeObservableCollection the BackgroundWorker can change it without causing the exception, (it uses  the Dispatcher when necessary)

The example solution

In attachment here the solution to implement the approach:

Change the Number of items in the texbox and click somewhere (defocus from the textbox) and the Bw to add data will be instantiated and executed (in async)

image

The lb on the right is bound to the special collection


public SafeObservableCollection<Item> Items
{
get
{
return _items;
}
set
{
_items = value;
OnPropertyChanged(this, "Items");
}
}

The  BackgroundWorker instance is defined using  a simple delegate that will do the job:


var bw = DefineBw(nItems, DoAdd);
bw.RunWorkerCompleted +=
(s, args) =>
{
if (!args.Cancelled)
{
bw = DefineBw(nItems, DoChange);
bw.RunWorkerAsync();
}
};

bw.RunWorkerAsync();

The DoAdd will add randomly the Items to the lb and when finished (if not cancelled) it defines in the queue another Bw to do some changes (this to show the difference in collection changes and items values hold in the collection itself)….

image

Last screenshot to show queued Bws and a cancel invocation, note the lb on the left with the actions history…

image

Conclusion

This is just an example of the major blocks to reach nice results, send me an email of add a comment if you need further details….

Reference

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.90).aspx

http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher(v=vs.90).aspx

http://msdn.microsoft.com/en-us/library/ms743695(v=vs.90).aspx

http://msdn.microsoft.com/en-us/library/bb613546(v=vs.90).aspx

more…

http://elegantcode.com/2009/07/03/wpf-multithreading-using-the-backgroundworker-and-reporting-the-progress-to-the-ui/

http://blogs.imeta.co.uk/jyoung/archive/2010/04/06/848.aspx

http://www.planetgeek.ch/2011/05/17/threadsafe-observablecollection/

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s