ARTICLE

Creating WPF window's on dedicated threads

Posted by Suchit Khanna Articles | WPF May 23, 2009
This article gives an insight to creating WPF windows in dedicated threads
Reader Level:
Download Files:
 

Creating Multi Threaded WPF Applications

There can be certain scenario's when you're application has to perform some heavy CPU intensive tasks and is running on UI thread (your WPF application) could drastically pull down the performance of your application as UI related tasks in WPF could themselves be extensive, as WPF forces all the UI work being done on the thread that created the UI . And for a UI intensive application (for example, which shows a real time streaming of data) with high resource consumption, the cost of rendering the visual could prove too much for the single thread. This in turn could lead to freezing of your UI.

If your application reaches to such a state it is always a better idea to create your resource intensive UI applications on dedicated threads, this article will give you an incremental approach to creating such an Application.

Single Threaded Application in WPF:

First create a WPF application in Visual Studio. Choose File->New->Project, then Visual C# -> WPF Application. Give appropriate name to the application and click "Ok"

Add the following piece of code to window1.xaml.cs:

using System.Windows;
using System.Threading;

namespace SingleThreadUI
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            Thread _thread = Thread.CurrentThread;
            this.DataContext = new { ThreadID = _thread.ManagedThreadId };
        }

        private void OnCreateNewWindow(object sender, RoutedEventArgs e)
        {
            Window1 w1 = new Window1();
            w1.Show();
        }
    }
}

In the constructor of the window1 class we create the data context containing thread's ID which could be used to bind to a TextBox or Label in the UI. A click event handler is also there which is used to create new Windows. The Window.xaml should look like this:

<Window x:Class="SingleThreadUI.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <StackPanel Orientation="Horizontal" Height="30">
            <TextBlock Text="Window created on :" FontSize="13"/>
            <TextBlock Text="{Binding ThreadID}" FontSize="13"/>
        </StackPanel>      
       
<Button Click="OnCreateNewWindow" Content="New Window" Width="100" Margin="10" Height="25"/>
    </StackPanel>
</
Window>

When we click on the New Window button, it will create clones of the window and one could see the ThreadId remains same for all the windows.

image1.gif

Here we are still creating the Window clones, but we wrapped the window creation code in Click event Handler of the New Window button.

Code for creating dedicated UI threads for each Window:

For creating WPF window on dedicated threads, Change the OnCreateNewWindow event Handler as:

private void OnCreateNewWindow(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(() =>
            {

                Window1 w = new Window1();
                w.Show();
               
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

Here the window creation code is exactly the same, except that we wrapped it in a thread delegate.

If you notice that we have to explicitly set new thread's apartment state to STA, this is WPF requirement.

Again, if you now click the "New Window", you could see that the application would crash, the reason is that our newly created thread is not enabled to support WPF window infrastructure i.e. it does not provide support for Windows pumping.

To fix the above problem,

WPF windows like other Windows rely on Windows message pump. In WPF we could do this by making use of Dispatcher class. For the main UI application WPF would take care of starting the dispatcher threads but for our own private UI thread, we have to explicitly start them. Lets see how we could do so:

private void OnCreateNewWindow(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(() =>
            {
 
                Window1 w = new Window1();
                w.Show();
                 
                System.Windows.Threading.Dispatcher.Run(); 

            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

This piece of code starts the message pump on it, now if you click the New Window button, you will get the fully functional window on a new thread.

There is one more issue to be solved; closing a particular window does not terminate this window's thread dispatcher, so the thread keeps running even after closing the window, the process will not close. The solution to this is that mark the thread as background thread. The proper implementations will gracefully shutdown the dispatcher when no longer needed.

private void OnCreateNewWindow(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(() =>
            {
                Window1 w = new Window1();
                w.Show();
                 w.Closed += (sender1, e1) => w.Dispatcher.InvokeShutdown();

                System.Windows.Threading.Dispatcher.Run();

            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
        }

The highlighted code shows the graceful exit of the window whenever it is closed and we have marked each thread to be run as a backgroubd thread.

The code above completes the task of shutting down the dispatcher for window's UI thread.

Login to add your contents and source code to this article
post comment
     

->I have used above code in my App. Problem i m getting is one of the Brush.Dispatcher.Thread is previous thread (i.e 't1'). ->While my current thread is 't2' ->'t1' is my previous thread on which i closed my window ->'t2' is new thread ->Brush is at common place and not creating new each time -> I m getting cross thread exception How to get rid of this problem? Please help ASAP

Posted by Milan Sangani Dec 05, 2012

HI, we are developing a application in VB.NET Can you convert the code in VB.NET, also we have a treeview and on each click of node we generate a report, which will take some time, so we need to show a window with a loading.gif file to make sure user know that something is happening. please provide a solution on this. do you have progress bar solution to it Thanks, Madu

Posted by Madhu sudhan Sep 07, 2011

Is it possible to have a Panel controlled by another thread?
or
Is it possible to enclose a wpf window that runs on a different thread inside a panel?

Posted by Roberto Valentini Sep 13, 2010
COMMENT USING
PREMIUM SPONSORS
Over-C is a holistic consortium of communications and technology specialists. We build, deploy and market both business as well as consumer products and solutions.
SPONSORED BY
  • PDF reports have never been easier to create. With our included WYSIWYG Designer, you can layout your reports, set up your data source and let DynamicPDF ReportWriter do the rest.
Join a Chapter