Posted by: Zeeshan Amjad | July 20, 2009

Threading in WPF


 

WPF Application starts with two threads. One for rendering that runs in background and other to manage the user interface. It is UI thread that is responsible for user input, handle events and draw everything on the screen. In WPF almost all of the objects belong to UI thread.

UI thread queues every work item along with its priority into the Dispatcher. Now it is Dispatcher who selects the work items one by one based on its priority. Every UI thread must have at least one Dispatcher. In addition each Dispatcher executes the work order in one thread only. If we try to access the user interface element that is created by another thread then we will get an exception. Here is a simple program to demonstrate this.

  1: using System;
  2: using System.Windows;
  3: using System.Threading;
  4: 
  5: public class wpf05
  6: {
  7:     static void ThreadFun(object obj)
  8:     {
  9:         Window win = (Window)obj;
 10:         if (win != null)
 11:         {
 12:             win.Title = "Writing from Thread";
 13:         }
 14:     }
 15: 
 16:     [STAThread]
 17:     public static void Main()
 18:     {
 19:         Window win = new Window();
 20:         win.Title = "Hello World";
 21: 
 22:         Thread th = new Thread(new ParameterizedThreadStart(ThreadFun));
 23:         th.Start(win);
 24: 
 25:         Application app = new Application();
 26:         app.Run(win);
 27:     }
 28: }
 29: 

This program will throw an InvalidOperationException because we are trying to modify the Window property from another thread. Also note that here we are also using System::Threading namespace.

Here is the simplest way to avoid this exception. But this program is not doing our required task.

  1: using System;
  2: using System.Windows;
  3: using System.Threading;
  4: using System.Windows.Threading;
  5: 
  6: public class wpf 
  7: {
  8:     static void ThreadFun(object obj)
  9:     {
 10:         Window win = (Window)obj;
 11:         if (win != null)
 12:         {
 13:             if (win.CheckAccess())
 14:             {
 15:                 win.Title = "Writing from Thread";
 16:             }
 17:         }
 18:     }
 19: 
 20:     [STAThread]
 21:     public static void Main()
 22:     {
 23:         Window win = new Window();
 24:         win.Title = "Hello World";
 25: 
 26:         Thread th = new Thread(new ParameterizedThreadStart(ThreadFun));
 27:         th.Start(win);
 28: 
 29:         Application app = new Application();
 30:         app.Run(win);
 31:     }
 32: }

 

In WPF only one thread can update the UI. If any other wants to update the user interface then it will request by using the Dispatcher class to perform that operation. Here is the proper way to update the User interface element from another thread.

  1: using System;
  2: using System.Windows;
  3: using System.Threading;
  4: using System.Windows.Threading;
  5: 
  6: public class MyWindow : Window
  7: {
  8:     private delegate void MyDelegate(String str);
  9: 
 10:     public MyWindow()
 11:     {        
 12:         Title = "Hello World";
 13:     }
 14: 
 15:     public void SetTitle(String title)
 16:     {
 17:         Thread.Sleep(3000);
 18:         Title = title;
 19:     }
 20: 
 21:     public void ThreadFun()
 22:     {
 23:         MyDelegate setTitle = SetTitle;
 24:         Dispatcher.BeginInvoke(DispatcherPriority.Normal,
 25:             setTitle, "Hello World from Thread");
 26:     }
 27: 
 28:     public void StartThread()
 29:     {
 30:         Thread th = new Thread(ThreadFun);
 31:         th.Start();
 32:     }
 33: }
 34: 
 35: public class wpf 
 36: {
 37: 
 38:     [STAThread]
 39:     public static void Main()
 40:     {
 41:         MyWindow win = new MyWindow();
 42: 
 43:         win.StartThread();
 44: 
 45:         Application app = new Application();
 46:         app.Run(win);
 47:     }
 48: }
 49: 

This program will change the title of main window from “Hello World” to “Hello World from Thread”.

We don’t have to create a delegate and instance of it for such a small work. We can also take an advantage of C# 2008 and create anonymous method for the delegate. Here is the same program with anonymous method.

  1: using System;
  2: using System.Windows;
  3: using System.Threading;
  4: using System.Windows.Threading;
  5: 
  6: public class MyWindow : Window
  7: {
  8:     public MyWindow()
  9:     {        
 10:         Title = "Hello World";
 11:     }
 12: 
 13:     public void ThreadFun()
 14:     {
 15:         Dispatcher.BeginInvoke(DispatcherPriority.Normal,
 16:             (ThreadStart) delegate 
 17:                 {
 18:                     Thread.Sleep(3000);
 19:                     Title = "Hello World from Thread"; 
 20:                 }
 21:             );
 22:     }
 23: 
 24:     public void StartThread()
 25:     {
 26:         Thread th = new Thread(ThreadFun);
 27:         th.Start();
 28:     }
 29: }
 30: 
 31: public class wpf 
 32: {
 33: 
 34:     [STAThread]
 35:     public static void Main()
 36:     {
 37:         MyWindow win = new MyWindow();
 38: 
 39:         win.StartThread();
 40: 
 41:         Application app = new Application();
 42:         app.Run(win);
 43:     }
 44: }
 45: 
Advertisements

Responses

  1. […] threading with Lambda expression We saw two examples of threading here and here. But in both cases we are creating delegate to perform the threading. For small tasks it […]


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

Categories

%d bloggers like this: