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/

Databinding in XAML for newbies (like me)

I never worked before with XAML and WPF, so I am looking to master the fundamentals concepts as soon I can to avoid stopper on the project I am working on; if you are a newbie on MVVM and XAML is a good idea to be familiar with the inspiring concept behind the separation of concerns.

XAML is a markup language where that uses controls and panels. The controls can contain others controls without changing
the behaviour of the controls itself. What does it mean? It means the behaviour of what the parent control can do is kept whatever it contains; controls behaviours doesn’t change when we change the layout, with a clear separation of them. The hierarchical structure defines the so-called visual tree, made up of controls and panels; the latter to define the layout of the XAML view. To make possible this, we need to change the idea of how bind data to the Presentation layer, the link between the View and the Model is done through the Binding in the XAML file, defining where to bind the Model and what to bind (Property of the Business Objects for example). Defining a “signpost” where to place the data at runtime, it make possible to change the layout/view without writing specific code… this is separation of concerns

Ex

My view is a rectangle and in the middle I want to show the Name of an object of the type Person

My view is a ellipse and in the middle I want to show the Name of an object of the type Person

Defining things with signpost (Binding) make this easier whatever the View is at runtime:

The concepts of Binding together with the Visual Tree makes possible to define a DataContext that will be inherited in the visual tree by each controls in it; this is very powerful you can refer to the Model anywhere you want and plus there is no type checking at compile time; the advantage is that the View doesn’t care to know which Model is used at runtime, the Model needs only to expose the property with the name in the XAML


<Ellipse Fill=”{Binding Color}”></Ellipse>


<Rectangle Fill=”{Binding Color}”></Rectangle>

So never so again something like

textBox1.Text = MyObject.Prop1;

but

<TextBox Text=”{Binding Prop1}”></TextBox>

+

this.DataContext = MyObjects // of anytype having at least Prop1 in the property defintion…

A very good starting point I found on the web are:

NYC DevReady: MVVM Content

  Title Speaker Content Links
Session 1 Demystifying XAML: Achieving Your Moment Of Clarity Miguel Castro Video Recording
Presentation Slides
Demo Code
Session 2 Programming with MVVM – Part 1 Miguel Castro Video Recording
Presentation Slides
Demo Code
Session 3 Programming with MVVM – Part 2 Miguel Castro Video Recording
Presentation Slides
Demo Code
Session 4 How Using MVVM Saved My Butt and How Laziness Came Back To Bite Me Danilo Diaz Video Recording
Presentation Slides
Session 5 Leveraging MVVM Inside PRISM Seth Juarez Video Recording
Presentation Slides

I suggest spending some time watching the recording, it will save a lot of time and it will help you to put on track (the right one) from the beginning

In attachment a VS2010 example that shows a Binding example in a listbox defining a template, note the behaviour of the listbox doesn’t change even the listboxitem are quite complex…

The Model is given by the class NationsRepository : List<Nation>

All the magic happens here

In the code behind (but not only here) we define the DataContext, where the data comes from at runtime,

NationsRepository.NationsRepository nationsRepository = new NationsRepository.NationsRepository();
this.DataContext = nationsRepository.GetSomePersistenData();

The XAML where we define Layout using Controls and Panels; note the ListBox Items are defined as a complex control, but still the behaviour is the change, check the screenshots:


<ListBox ItemsSource="{Binding}" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel  Orientation="Horizontal" >
                        <Rectangle  Height="16" Width="16" Margin="1,1,1,1" Fill="Red"></Rectangle>
                        <Label Content="{Binding Name}" FontStyle="Italic"></Label>
                        <TextBox Text="{Binding Population, StringFormat=Population: {0:N}}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

Ex:

You can click on the listbox items as expected)

You can click in the textbox in the listbox item