Mike’s Dump

January 15, 2006

.NET Compact Framework – Updating the User Interface from a Worker Thread

Filed under: Code — mikesdump @ 12:06 pm

Before you go ahead and update the UI from another thread using the .NET Compact Framework ask yourself the following:

“Self, do I like predictability or unpredictability?”

If you answered predictability then you can skip ahead to “What you should do after you got it wrong”. If you answered unpredictability then proceed to “Don’t be a moron, Mike already tried that”

Don’t be a moron, Mike already tried that
In my own defence I didn’t realize at the time the event was firing from a thread outside the main UI thread (I’m not sure if that is much of an excuse)

Anyways, you like unpredictability eh? I’m guessing when you are updating your UI from a worker thread you are doing something like this:

Private workerThread As Thread
Private shuttingDown As Boolean

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
workerThread = New Thread(AddressOf UpdateUIFromWorkerThread)
workerThread.Start()

End Sub

Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
shuttingDown = True

End Sub

Private Sub UpdateUIFromWorkerThread()
Dim counter As Integer


While shuttingDown = False
Label1.Text = counter.ToString()
counter += 1
Thread.Sleep(500)
End While

End Sub

What is happening here is a worker thread is created when this CE application first starts. The thread enters a loop that won’t end until the form is closed. In the loop a label is updated with the value of a counter which is incremented every half second.

When I tried this in the emulator it actually is predictable. Both attempts locked up the emulator and I wasn’t able to shutdown the application. I’ve seen more complicated applications updating the UI from a worker thread that weren’t so consistent.
In short, don’t update the UI from outside the main UI thread. UI controls are not thread safe.

What you should do after you got it wrong
There are many things you should be doing after getting it wrong the first time. The key to getting it right is completing the steps below in order.

1) Swear at your computer and/or CE device
2) Grab another beer (if you aren’t currently drinking that is another mistake)
3) Read the right freak’in documentation

Sure, you are thinking this is a simple problem. I just need to use that “control.invoke” thingy and all will be well. The answer is yes and no. The compact framework way is below.

Private workerThread As Thread
Private shuttingDown As Boolean
Private counter As Integer

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
workerThread = New Thread(AddressOf UseInvokeInsteadOfDirectlyUpdatingUI)
workerThread.Start()

End Sub

Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
shuttingDown = True

End Sub

Private Sub UseInvokeInsteadOfDirectlyUpdatingUI()
While shuttingDown = False
Me.Label1.Invoke(New EventHandler(AddressOf WorkerThreadPlayingNiceWithTheUI))
counter += 1
Thread.Sleep(500)
End While

End Sub

Private Sub WorkerThreadPlayingNiceWithTheUI(ByVal sender As Object, ByVal e As System.EventArgs)
Label1.Text = counter.ToString()
End Sub

There are only a couple small changes from the previous version of this code.

1) counter is no longer a local variable to the worker thread method (UseInvokeInsteadOfDirectlyUpdatingUI())
2) The worker thread method calls Me.Label1.Invoke which will call WorkerThreadPlayingNiceWithTheUI
3) WorkerThreadPlayingNiceWithTheUI uses the member level variable counter to update the label.

What gave me a little bit of grief was I was reading a post I found on invoke which would be fine for the desktop but didn’t work in the compact framework (I can’t recall for sure but I believe I got an ArguementException when attempting it this way).

On the desktop the invoke method is overloaded and you would be able to pass the value of “counter” to the method directly instead of making it a member variable. I would prefer this over declaring the counter at the class level but it doesn’t appear to be an option for the compact framework.

The second thing that got me is that the delegate must be of type EventHandler for the compact framework (also this is something this post told me not to do).

The last item to note in the MSDN documentation which I don’t think applies in this case is:

An important point to note is that you must call Application.DoEvents() in your code if you are updating the UI in the worker thread. Calling Application.DoEvents() will make sure that any events raised by the worker thread are processed by the UI thread.

Looking at the example on that page the UI thread was blocking for one second. Just before the sleep call it was calling Application.DoEvents() which would process any events waiting to be processed by the worker thread. Since in my example the UI thread isn’t blocking at any point the Invoke calls are completed as expected.

The moral of the story: Don’t just read the documentation, read the right documentation.

kick it on dotnetkicks.com

Advertisements

4 Comments »

  1. Just when you thought it was safe to enter the water, there it is.
    Slowing the music gets louder (you’ll…

    Comment by Mike's Dump — January 20, 2006 @ 9:26 pm | Reply

  2. Trackback from dotnetkicks.com

    Comment by dotnetkicks.com — May 30, 2006 @ 6:50 pm | Reply

  3. Hi Mike, I wanted to thank you for your article, I was looking for help but nobody explained this topic as clearly as you did. It worked for me pretty well. Thank you so much.

    Comment by VicPulido — June 5, 2008 @ 8:11 am | Reply

  4. Glad it helped

    Comment by mikesdump — June 5, 2008 @ 9:16 am | Reply


RSS feed for comments on this post. TrackBack URI

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

Create a free website or blog at WordPress.com.

%d bloggers like this: