C# 01: Update UI control from background thread in WPF with Dispatcher



Here is a summary of the background knowledge that is directly related to the topic of this tutorial:
(1) WPF is STA (Single-Threaded Apartment) application
(2) UI controls can only be created on STA thread
(3) A control can only be accessed on the same thread it is originally created

Since they are self-explanatory, I won’t spend time explaining them. Instead, we will go through a WPF program to illustrate how they affect the behavior, or require dispatcher class.

(Demo starts)

I am using Visual Studio 2017. Create a new WPF application. Select template: WPF App using .NET Framework. The default .NET version is 4.5. Check “Create directory for solution”. Save to the location of your preference.

Before we make any change, run the program with Ctrl + F5. Make sure no problem.

Right-click on the source code tab. Select “open containing folder”. Look at the attribute for Main() in the folder objDebug. Open automatically generated file App.g.cs. App is defined as partial class. The attribute for Main() method is declared as STA thread. This clarifies our first statement: WPF is STA (Single-Threaded Apartment) application. There is nothing for us to modify here. It just helps us to understand better the nature of WPF application.

[System.STAThreadAttribute()]
public static void Main()
{
}

Come back to Visual Studio. Open Toolbox with shortcut Ctrl + Alt + X, add two buttons and one label to the main window design area.

Now update their properties in Properties pane. Change the name of the label to “lblMessage”, and text size to 72 px. Change the name of left button to “btnOnce”, text size to 48 px, and content to “Once”. Change the name of right button to “btnContinuous”, text size to 48 px, and content to “Continuous”. Adjust the control size if necessary.

That’s all for our GUI design. Run the program and you shouldn’t see any error.

Double click on buttons to add click event handlers. Now we have event handlers for both button Once and button Continuous.

Add a class scope variable _count as integer and assign 0. It’s optional to add private access modifier. It’s default to private.

Implement button Once event handler. Increment _count variable. Update message label with number of clicks. Run the program. Click button several times. The message is updated accordingly.

So far we are updating UI label control from UI thread. It works flawless.

Now assume we want to call a long running method to alternate label background color from red to yellow, back and forth every half a second. First, let’s find out what could happen if this method is called in UI thread.

Add a method to update label background, accepting integer state as parameter. Use switch block to decide which background color is applied to label: red when state is 1, yellow when state is 2. This is a simple routine.

Add another method, without a better name, we call it Long_running. To display the possible exception message, that we expect will happen at some point in this tutorial, add try catch block. Use message box to show the exception details. Use endless loop to simulate a long running process. Set delay to 500 ms. Call update label background method with argument 1 and 2 with interval as defined.

Now call Long_running method from button Continuous event handler. How bad it could be? Let’s run the program and find out.

Click button “Once”. It works as before.

Now click button “Continuous”. Do you expect smoke and flames? Actually no, the application is simply frozen, not responding. Try to close the program. It complains the application is not responding.

OK, that’s understandable. We shouldn’t block the UI thread with long running process, otherwise, bad things happen.

Of course, there are some work around, like using timer, to alternate background color in the UI thread. But that’s not what I want to focus on in this tutorial. We want to put this long running process in the background thread.

(demo ends)

Here is the complete code:
(1) part 1 with button Once event handler
(2) part 2 with button Continuous event handler, and update label background method
(3) the essential code is in part 3 with Dispatcher BeginnInvoke implementation in Long_running method

The complete program can be also be found at Github with this link:
https://github.com/lileowang/Demo_cs/tree/master/Cs_tutorial_01_WPF_dispatcher

Here is a brief recall of what we have learned:
(1) WPF is STA application
(2) UI controls can only be created and accessed on UI thread
(3) To access UI controls from non-UI thread, Dispatcher must be used

Thanks for watching!

Comments are closed.