How to run a function on a background thread for Windows Phone 7? How to run a function on a background thread for Windows Phone 7? multithreading multithreading

How to run a function on a background thread for Windows Phone 7?


Here's how I'd approach a solution to this.

Your ViewModel implements INotifyPropertyChanged right? There's no need to dispatch the Events. Just raise them "bare" in the Model, then dispatch the RaisePropertyChanged in the ViewModel.

And yes, you should have some sort of singleton model/database in your code. After all, what is a SQL Database if not some gigantic singleton? Since we don't have a database in WP7, don't be shy creating a singleton object. I have one called "Database" :)

I've just tried threading my dataloads in there, and realise that in fact the best approach is simply implementing INotifyPropertyChanged right down at the model level. There's no shame in this.

So given that, here's what I'm doing in the singleton Database object to load and return my Tours "table" (note the thread.sleep to make it take a visible amount of time to load, normally its sub 100ms). Database class now implements INotifyPropertyChanged, and raises events when loading is completed:

public ObservableCollection<Tour> Tours{  get  {    if ( _tours == null )    {      _tours = new ObservableCollection<Tour>();      ThreadPool.QueueUserWorkItem(LoadTours);    }    return _tours;  }}private void LoadTours(object o){  var start = DateTime.Now;  //simlate lots of work   Thread.Sleep(5000);  _tours = IsoStore.Deserialize<ObservableCollection<Tour>>( ToursFilename ) ??  new ObservableCollection<Tour>();  Debug.WriteLine( "Deserialize time: " + DateTime.Now.Subtract( start ).ToString() );  RaisePropertyChanged("Tours");}

You follow? I'm deserializing the Tour list on a background thread, then raising a propertychanged event.

Now in the ViewModel, I want a list of TourViewModels to bind to, which I select with a linq query once I see that the Tours table has changed. It's probably a bit cheap to listen for the Database event in the ViewModel - it might be "nicer" to encapsulate that in the model, but let's not make work we we don't need to eh?

Hook the Database event in the Viewmodel's constructor:

public TourViewModel(){Database.Instance.PropertyChanged += DatabasePropertyChanged;}

Listen for the appropriate table change (we love magic strings! ;-) ):

private void DatabasePropertyChanged(object sender, PropertyChangedEventArgs e){  if(e.PropertyName == "Tours")  {    LoadTourList();  }}

Select the records I want from the table, then tell the view there is new data:

public void LoadTourList(){  AllTours = ( from t in Database.Instance.Tours    select new TourViewModel( t ) ).ToList();  RaisePropertyChanged( "AllTours" );}

And lastly, in your ViewModelBase, it's best to check if your RaisePropertyChanged needs dispatching. My "SafeDispatch" method is pretty much the same as the one from MVVMlight:

private void RaisePropertyChanged(string property){  if ( PropertyChanged != null )  {    UiHelper.SafeDispatch(() =>      PropertyChanged(this, new PropertyChangedEventArgs(property)));  }}

This works perfectly in my code, and I think is fairly tidy?

Lastly, extra for experts: in WP7, it might be good to add a ProgressBar with IsIndeterminate=True to your page - this will display the "dotted" progress bar. Then what you can do is when the ViewModel first loads you could set a "ProgressBarVisible" property to Visible (and raise the associated PropertyChanged event). Bind the ProgressBar's visibility to this ViewModel property. When the Database PropertyChanged event fires, set the visibility to Collapsed to make the progressbar go away.

This way the user will see the "IsIndeterminate" progress bar at the top of their screen while the deserialization is running. Nice!


I have not developed for WP7 before, but I found this article that might be useful!

Here is the Dining Philosopher sample code from the article that should give you a good idea on how to raise an event to the UI from another thread:

public DinnersViewModel(IDinnerCatalog catalog){    theCatalog = catalog;    theCatalog.DinnerLoadingComplete +=        new EventHandler<DinnerLoadingEventArgs>(              Dinners_DinnerLoadingComplete);}public void LoadDinners(){    theCatalog.GetDinners();}void Dinners_DinnerLoadingComplete(    object sender, DinnerLoadingEventArgs e){    // Fire Event on UI Thread    View.Dispatcher.BeginInvoke(() =>        {            // Clear the list            theDinners.Clear();            // Add the new Dinners            foreach (Dinner d in e.Results)                theDinners.Add(d);            if (LoadComplete != null)                LoadComplete(this, null);        });}

I hope it's helpful :).

One thing that's confusing: you said that when you use the helper to raise the event, then VS2010 crashes... what exactly are you seeing when it's crashing? Are you getting an exception?


Jeff, I'm still figuring this stuff out myself. I posted a similar question and ended up answering it myself by building a simple sample. Here:

A super-simple MVVM-Light WP7 sample?

The summary is:

1) I derived my Model (yes my model) from ViewModelBase. This gives me Mvvm-Light's implementation of messaging and INotifyPropertyChanged which is handy. You could argue this is not "pure" but I don't think it matters.

2) I used Mvvm-Light DispatcherHelper.CheckBeginInvokeOnUIhelper just as you did (from my Model, NOT my ViewModel).

Hope this helps.