Geeks With Blogs
Pedro Dias

Following up on a previous blog post where I exemplify databinding to objects, a reader was having some trouble with getting the UI to update.

Here’s the rough UI:

image

The idea is, when pressing Start, a background worker process starts ticking at the specified interval, then proceeds to increment the databound Elapsed value.

The problem is that event propagation is limeted to current thread, meaning, you fire an event in one thread, then other threads of the same application will not catch it.

The Code behind

So, somewhere in my ViewModel, I have a corresponding bethod Start that initiates a background worker, for example:

public void Start( )
{
    BackgroundWorker backgroundWorker = new BackgroundWorker( );
    backgroundWorker.DoWork += IncrementTimerValue;
    backgroundWorker.RunWorkerAsync( );
}

protected void IncrementTimerValue( object sender, DoWorkEventArgs e )
{
    do
    {
        if( this.ElapsedMs == 100 )
            this.ElapsedMs = 0;
        else
            this.ElapsedMs++;

    }while( true );
}
Assuming that there is a property: 
public int ElapsedMs
{
    get { return _elapsedMs; }
    set
    {
        if( _elapsedMs == value )
            return;

        _elapsedMs = value;
        NotifyThatPropertyChanged( "ElapsedMs" );
    }
}

The above code will not work. If you step into this code in debug, you will find that INotifyPropertyChanged is called, but it does so in a different thread, and thus the UI never catches it, and does not update.

One solution

Knowing that the background thread updates the ElapsedMs member gives me a chance to activate BackgroundWorker class’ progress reporting mechanism to simply alert the main thread that something has happened, and that it is probably a good idea to refresh the ElapsedMs binding.

public void Start( )
{
    BackgroundWorker backgroundWorker = new BackgroundWorker( );
    backgroundWorker.DoWork += IncrementTimerValue;

    // Listen for progress report events
    backgroundWorker.WorkerReportsProgress = true;

    // Tell the UI that ElapsedMs needs to update
    backgroundWorker.ProgressChanged +=
        ( sender, e ) =>
            {
                NotifyThatPropertyChanged( "ElapsedMs" );
            };
    backgroundWorker.RunWorkerAsync( );
}

protected void IncrementTimerValue( object sender, DoWorkEventArgs e )
{
    do
    {
        Thread.Sleep( IntervalMs );
        if( this.ElapsedMs == 100 )
            this.ElapsedMs = 0;
        else
            this.ElapsedMs++;

        // report any progress
        ( sender as BackgroundWorker ).ReportProgress( 0 );

    }while( true );
}

What happens above now is that I’ve used the BackgroundWorker cross thread mechanism to alert me of when it is ok for the UI to update it’s ElapsedMs field.

Because the property itself is being updated in a different thread, I’m removing the NotifyThatPropertyChanged call from it’s Set method, and moving that responsability to the anonymous method that I created in the Start method.

This is one way of solving the issue of having a background thread update your UI. I would be happy to hear of other cross-threading mechanisms for working in a MCP/MVC/MVVM pattern.

Posted on Friday, April 30, 2010 1:17 AM | Back to top


Comments on this post: Using INotifyPropertyChanged in background threads

# re: Using INotifyPropertyChanged in background threads
Requesting Gravatar...
This really isn't how INotifyPropertyChanged was meant to be used. It should be internal to the object class.

Also, I'm not sure if you have the BW in the class or the UI, but I try to avoid using BW in an object class, if I have a long running operation, I try to put in a separate thread. I've had mixed results with BW outside of the UI.

If you absolutely have to update the UI from a background thread, you need to do so in a delegate. This may work fine in development, but it will eventually blow up in production. WPF makes this pretty easy with the Dispatcher, it looks like you're using WinForms; I'm a bit rusty with them.

Good luck!
Left by Tim Hibbard on May 02, 2010 9:45 PM

# re: Using INotifyPropertyChanged in background threads
Requesting Gravatar...
Thanks for the comments, Tim. I'm not sure what you mean by saying that INotifyPropertyChanged should be internal to an Object Class, are you speaking of a POCO/DTO? The code I've posted is a ViewModel (controller or presenter if you will), where it is perfectly sound to both start background processes, commands as well as keeping mapped values to an object represented elsewhere.

The viewmodel iteself does not have any form of dependency to the view (in this case a Windows Form) and could just as well have been a wpf or silverlight UI with just minor modifications.

I know the code I posted is fragile in many respects, there is no concern about threading for one, another is mapping to a dto or service for transfer, both would just get in the way of the point that I was making.

Using some imagination, I am sure that you can imagine a service running in a background thread that is updating some data that the UI needs to display. The example I posted, as I conclude, is ONE way of doing just that. Another way, is to use the mediator pattern, but again, that's a more complex solution, and often, overkill.

The essence is that cross thread event mechanism is complicated, and my post offers a simple, practical way out that will work for simple scenarios. The price to pay is a code smell; calling INotifyPropertyChanged from somewhere other than the property's setter, but for all practical intents and purposes, it saves me time, and my client money, and I still have 100% test coverage at the end of the day :)
Left by Pedro Dias on May 03, 2010 12:52 AM

Your comment:
 (will show your gravatar)


Copyright © digitaldias | Powered by: GeeksWithBlogs.net