Saturday, November 24, 2012

WPF Start New Background Process using Task

In GUI programming there is exist some very common problem - if some operation takes too much time the GUI will become unresponsive. For example, if you want establish connection with a server, or fetch some data from database or a large file, this probably will take some time and if you perform this operation in the main thread your GUI will stuck. In order to keep your GUI responsive you need to run long-running operations on a separate thread. So far, in order to open a new thread we used Thread class or BackgroundWorkerStarting from .NET Framework 4.0 we have a Task class for this purpose. 

If you already switched to Visual Studio 2012 with Framework 4.5 then read my previous post - C# Async Programming Example in WPF (Async, Await).
If you still working with Visual Studio 2010 Framework 4.0 then this post is for you.
Today I'll show how to build WPF application with background thread using Task Framework 4.0.

WPF with new background process using Task Framework 4.0

Ok, let's say we have a WPF application with a button which triggers some long-running method. 
Here is the XAML:
<Window x:Class="WpfTask.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="CodeArsenal.net" Height="200" Width="300">
    
    <DockPanel Margin="4">
        <Button Name="buttonNewTask" Height="50" 
                Content="New Task" DockPanel.Dock="Top" 
                Click="buttonNewTask_Click"/>

        <TextBox Name="textBoxResults" DockPanel.Dock="Bottom" Margin="0,10,0,0"
                 TextWrapping="Wrap"
                 FontFamily="Lucida Console" 
                 FontSize="10"
                 AcceptsReturn="True"/>
    </DockPanel>
</Window>
So, by pressing on buttonNewTask we call for buttonNewTask_Click method. Now we want run this method in separate thread and after the method is completed we want to show the result. This is how to do it in .NET Framework 4.0 using Task:
private void buttonNewTask_Click(object sender, RoutedEventArgs e)
{
    textBoxResults.Text = "Working...";
    buttonNewTask.IsEnabled = false;

    TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
    CancellationToken cancelationToken = new CancellationToken();

    string result = "";
    Task.Factory.StartNew(() => GetResultFromServer(out result)).
        ContinueWith(w =>
        {
            textBoxResults.Text = result;
            buttonNewTask.IsEnabled = true;
        },
        cancelationToken,
        TaskContinuationOptions.None, scheduler);
}

private void GetResultFromServer(out string result)
{
   Thread.Sleep(2500);
   result = "Data received.";
}
Task.Factory.StartNew actually starts a mew thread. I specified GetResultFromServer as the one which will run in new thread. Inside ContnueWith block we put everything that should run after the GetResultFromServer is complete - printing the result and enabling the button. We don't use CancelationToken in this particular example, but its mandatory to specify it. We also must declare the TaskScheduler which tells to Task Framework what our GUI thread is, so it know when to run the the final update.
WPF with new background process using Task Framework 4.0 - Thread completed

Download the source code (Visual Studio 2010 project).

4 comments: