Moving back to People & Groups Framework - WPF Data Binding

Okay, hello again. Let's go back to our People & Groups Framework - right now I've reworked the solution, as I told before, moved to Codeplex, and, finally, work in a current, M0 (stands for Milestone 0 :)) branch using VSTS 2008 and Team Foundation Server! :) Okay, enough for bravado. 

So few problems I've got while testing an app:

  • UI of a testing App is really unresponsive while querying the underlining database, that is provided by excellent Base4.net, because we do not need to get people from database (which is an easy part of the problem), but also need to get their presence, which makes us to need to make a call to underlying provider and get presence for that Person.
  • Currently, if there is no IM client running, by design provider doesn't respond (in constructor, it tries to access data from Skype say, but as far as Skype is not running, it fails), this is really easy to address by making changes to Contract and changing default constructor resolved

WPF Data Binding

The problem: currently the testing app when asked to retrieve contacts from database is becoming unresponsive.

The solution: find out a way to make populating the list box with contact controls in a way when UI continues being responsive.

How?

This is a great question :)

First, we need to move all job on Populating data into separate, non-UI thread. Why?

Typical problem of Windows applications is that all the job is done in UI thread, the same one where user interacts with app --> Thus each time the operation your user requests from an app consumes lots of time --> your application becomes unresponsive, and thus --> your user becomes unhappy.

To avoid this, the common practice is to move all job to background thread, this will enable our user to make all operations in a way she expects the app to do its job, while the second thread will take care of task it got, and when finished (on while getting results) the UI of an app will change, showing items as they arrive.

Look a this illustration:

image

Here we have:

User, Application, some Database Store.

Let's see the steps the solution should do to accomplish our needs:

  1. User selects some operation in Application
  2. Application catchs the User's input in first, UI Thread, and moves it to second, Background Thread (BG)
  3. Background thread makes a request to Database Store
  4. Database Store returns data back to BG Thread
  5. BG Thread returns data from Database Store back to UI Thread
  6. and UI Thread owns what User sees - she gets updated information from Database Store

What is cool here, during all these steps the UI Thread continues being responsive - and that's our goal! :)

Now 101 WPF Data Binding

  1. To make separation, we need to have an Observable Collection in which we will put data from the store, and which will be updatable - see here for wonderful sample: Data Binding & Multi-threading in WPF
  2. This Observable Collection will be generic one, and we will populate it with special item, named say as SemContact, which supports INotifyPropertyChanged interface which enables WPF to track changes
  3. We need to call method to pull this collection with data from another thread
  4. We add ListBox to the window of our test app
  5. We modify existing ContactLisBoxItem control to support dependency properties (because, w/o them, WPF would not help us in binding data) - look here for explanations: Dependency Properties
  6. We set that ContactListBoxItem to DataTemplate inside ItemTemplate section of ListBox in XAML declaration of our Test App

All other stuff will remain the same, but we will not populate the ListBox itself with new data while quering Contacts storage, but rather populate our Observable Collection with SemContact. WPF Databinding will do the job for us:

image image
Our app before pressing button "Refresh" Our app while po
image  
Our app with some populated data  

also you can't see if app is really behaving as usual after pressing the "Refresh" button, I can prove it works, and you can try sources - this is the ChangeSet I just built to show this example.

Prerequisites:

  • You need to download all goodies
  • Download Base4.net (last version) from https://www.base4.net/base4.net.aspx
  • add a database DefaultStore to it
  • upload three schemas, SemFx.Core, SemFx.WLM, SemFx.Skype to it
  • create a folder SemFx in Program Files and give modify access (all access) to Everyone
  • then download the solution
  • delete bindings to TFS
  • build it
  • be sure all results are in %ProgramFiles%\SemFx\v0.1\ folder
  • find out executable (there should be one)
  • be sure to have at least one of two IM Clients that are supported by now: Windows Live Messenger or Skype
  • Try the app :)

If you will get into trouble I'd be interested to help you!

CYA! :)