Threads in WPF

Introduction

Threading enables a program to do concurrent processing so that it can do more than one operation at a time. Window Presentation Foundation (WPF) has been designed such that it saves the developer from the difficulties of threading. This article can help you to understand the proper use of threading in WPF.

WPF Internal threads and rules

All WPF applications run with a minimum of the following two threads:

  1. For rendering: It runs in the background, so it is hidden.

  2. For managing UI interface (UI thread): Most of the WPF objects are tied with UI threads. It receives input, paints the screen, runs code and handles events.

WPF supports a single-threaded apartment model that has the following rules:

  1. One thread runs in the entire application and owns all the WPF objects.

  2. WPF elements have thread affinity, in other words other threads can't interact with each other.

  3. WPF objects that have thread affinity derive from the Dispatcher object.

Thread handling in WPF by developer

When creating an application in WPF the developer must sometimes manage the threads, so it provides some way to handle and use the thread in the application on various scenarios. The following are the two ways for handling the threads:

  1. The Dispatcher
  2. The Background Worker.

The Dispatcher

The Dispatcher is an instance of the System.Windows.Threading.Dispatcher class. It owns the application thread and manages a queue of work items. It executes UI operations in a First in First Out (FIFO) manner by taking priority of each. It does not create a new thread. It is not multi-threaded.

Every Visual WPF object derives from a DispatcherObject. It is an object that is linked to the DispatcherObject class. The following are the members of the DispatcherObject class:

  1. Properties

    1. Dispatcher: It gets a Dispatcher.

  2. Methods

    There are several methods in the DispatcherObject Class. Some important methods are the following:

    1. CheckAccess(): It returns true if the code is a thread that can use the object.

    2. VerifyAccess(): Does nothing if the code is in the correct thread to use the object otherwise it throws an “InvalidOperationException”.

    3. GetType(): It gets the type of current instance.

    WPF objects call VerifyAccess() frequently to project themselves.

Why do we need Dispatcher?

An example that will clarify the need of Dispatcher in WPF Application:

  1. using System;  
  2.   
  3. using System.Threading;  
  4.   
  5. using System.Windows;  
  6.   
  7. namespace WpfApplication1  
  8. {  
  9.   
  10.     /// <summary>    
  11.   
  12.     /// Interaction logic for WPF UI Upadation using    
  13.   
  14.     /// thread.    
  15.   
  16.     /// </summary>    
  17.   
  18.     public partial class MainWindow : Window  
  19.     {  
  20.   
  21.         public MainWindow()  
  22.         {  
  23.   
  24.             InitializeComponent();  
  25.   
  26.         }  
  27.   
  28.         private void MyButton_Click(object sender, RoutedEventArgs e)  
  29.         {  
  30.   
  31.             Thread thread = new Thread(UpdateText);  
  32.   
  33.             thread.Start();  
  34.   
  35.   
  36.         }  
  37.   
  38.         private void UpdateText()  
  39.         {  
  40.   
  41.             Thread.Sleep(TimeSpan.FromSeconds(5));  
  42.   
  43.             TxtName.Text = "Hello Geeks !";  
  44.   
  45.         }  
  46.   
  47.     }  
  48.   
  49. }  
Now, this is the wrong code because the UpdateText() method will be executed on a new thread and that thread is not allowed to access WPF objects.

Method “VerifyAccess()” is called and an “InvalidOperationException” is thrown.

The following is the correction of the code above:
  1. using System;  
  2.   
  3. using System.Threading;  
  4.   
  5. using System.Windows;  
  6.   
  7. namespace WpfApplication1  
  8. {  
  9.   
  10.     /// <summary>    
  11.   
  12.     /// Interaction logic for WPF UI Upadation using    
  13.   
  14.     /// Dispatcher.    
  15.   
  16.     /// </summary>    
  17.   
  18.     public partial class MainWindow : Window  
  19.     {  
  20.   
  21.         public MainWindow()  
  22.         {  
  23.   
  24.             InitializeComponent();  
  25.   
  26.         }  
  27.   
  28.         private void MyButton_Click(object sender, RoutedEventArgs e)  
  29.         {  
  30.   
  31.             Thread thread = new Thread(UpdateText);  
  32.   
  33.             thread.Start();  
  34.   
  35.             ;  
  36.   
  37.         }  
  38.   
  39.         private void UpdateText()  
  40.         {  
  41.   
  42.             Thread.Sleep(TimeSpan.FromSeconds(5));  
  43.   
  44.             this.Dispatcher.BeginInvoke(new Action(() =>  
  45.             {  
  46.   
  47.                 TxtName.Text = "Hello Geeks !";  
  48.   
  49.             }));  
  50.   
  51.         }  
  52.   
  53.     }  
  54.   
  55. }  
So, Dispatcher is the best way for updating a WPF UI with a thread.

The Background Worker

It is very beneficial in time-consuming tasks. It executes the code at the same time. It is invoked in a separate thread. It automatically synchronizes with the main thread of an application.

It is used to run an operation in the background and defers execution to the UI. The following are some cases where a Background worker can be used:

 

  1. If the user wants a responsive UI and faces delays in specific operations.

  2. Data download.

  3. Database transactions.

BackgroundWorker is a class under System.ComponentModel. It executes the operation on a separate thread.

  1. using System;  
  2.   
  3. using System.ComponentModel;  
  4.   
  5. using System.Threading;  
  6.   
  7. namespace BackGroundWorkerExample  
  8. {  
  9.   
  10.     /// <summary>    
  11.   
  12.     /// It implements backgroundworker.    
  13.   
  14.     /// </summary>    
  15.   
  16.     class Program  
  17.     {  
  18.   
  19.         private static BackgroundWorker backgroundWorker;  
  20.   
  21.         static void Main(string[] args)  
  22.         {  
  23.   
  24.             backgroundWorker = new BackgroundWorker  
  25.   
  26.             {  
  27.   
  28.                 WorkerReportsProgress = true,  
  29.   
  30.                 WorkerSupportsCancellation = true  
  31.   
  32.             };  
  33.   
  34.             //Event creation.    
  35.   
  36.             //For the performing operation in the background.    
  37.   
  38.             backgroundWorker.DoWork += backgroundWorker_DoWork;  
  39.   
  40.             //For the display of operation progress to UI.    
  41.   
  42.             backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;  
  43.   
  44.             //After the completation of operation.    
  45.   
  46.             backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;  
  47.   
  48.             backgroundWorker.RunWorkerAsync("Press Enter in the next 5 seconds to Cancel operation:");  
  49.   
  50.             Console.ReadLine();  
  51.   
  52.             if (backgroundWorker.IsBusy)  
  53.             {  
  54.   
  55.                 backgroundWorker.CancelAsync();  
  56.   
  57.                 Console.ReadLine();  
  58.   
  59.             }  
  60.   
  61.         }  
  62.   
  63.         /// <summary>    
  64.   
  65.         /// Performs operation in the background.    
  66.   
  67.         /// </summary>    
  68.   
  69.         /// <param name="sender"></param>    
  70.   
  71.         /// <param name="e"></param>    
  72.   
  73.         static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)  
  74.         {  
  75.   
  76.             for (int i = 0; i < 200; i++)  
  77.             {  
  78.   
  79.                 if (backgroundWorker.CancellationPending)  
  80.                 {  
  81.   
  82.                     e.Cancel = true;  
  83.   
  84.                     return;  
  85.   
  86.                 }  
  87.   
  88.                 backgroundWorker.ReportProgress(i);  
  89.   
  90.                 Thread.Sleep(1000);  
  91.   
  92.                 e.Result = 1000;  
  93.   
  94.             }  
  95.   
  96.         }  
  97.   
  98.         /// <summary>    
  99.   
  100.         /// Displays Progress changes to UI .    
  101.   
  102.         /// </summary>    
  103.   
  104.         /// <param name="sender"></param>    
  105.   
  106.         /// <param name="e"></param>    
  107.   
  108.         static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)  
  109.         {  
  110.   
  111.             Console.WriteLine("Completed" + e.ProgressPercentage + "%");  
  112.   
  113.         }  
  114.   
  115.         /// <summary>    
  116.   
  117.         /// Displays result of background performing operation.    
  118.   
  119.         /// </summary>    
  120.   
  121.         /// <param name="sender"></param>    
  122.   
  123.         /// <param name="e"></param>    
  124.   
  125.         static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
  126.         {  
  127.   
  128.             if (e.Cancelled)  
  129.             {  
  130.   
  131.                 Console.WriteLine("Operation Cancelled");  
  132.   
  133.             }  
  134.   
  135.             else if (e.Error != null)  
  136.             {  
  137.   
  138.                 Console.WriteLine("Error in Process :" + e.Error);  
  139.   
  140.             }  
  141.   
  142.             else  
  143.             {  
  144.   
  145.                 Console.WriteLine("Operation Completed :" + e.Result);  
  146.   
  147.             }  
  148.   
  149.         }  
  150.   
  151.     }  
  152.   
  153. }  
Output:

output


Difference between Dispatcher and Background Worker
 
  1. Background worker executes the code at the same time it is invoked in a separate thread. It automatically synchronizes with the main thread of a WPF application when the Dispatcher processes a queue of things to do every time.

  2. A Background worker executes in a separate thread whereas the dispatcher runs with the UI thread of a WPF application.

  3. If you want to run an operation in the background of the UI, use a background worker but use the Dispatcher to marshal updates back to the WPF UI.