Click here to Skip to main content
Click here to Skip to main content

How To: Manage cross-thread WinForms controls access

, 29 Jan 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Using Generics and Extension Methods to provide easy-to-use helper for cross thread operations over WinForms controls.

Introduction   

When developing rich business applications, developers often have to deal with manipulating data and UI on separate threads and so have to manage cross-thread controls access.

In WinForms, we do that by using callback methods and invoke them on the main thread.

For example, consider a heavy load worker that searches some files into the computer and sends back log information during the process. We should implement a method that handles the event:

private void AppendLogText(string logText)
{
    if (tbLog.InvokeRequired)
    {
        AppendLogTextCallBack callBack = new AppendLogTextCallBack(AppendLogText);
        Invoke(callBack, new object[] { logText });
    }
    else
    {
        if (!string.IsNullOrEmpty(tbLog.Text))
            tbLog.AppendText(Environment.NewLine);
        tbLog.AppendText(string.Concat(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"), " : ", logText));
    }
}

This article will show how to implement methods to simplify cross thread controls access implementation.

Background

In this article, we use the TPL (Task Parallel Library) to run worker async. The TPL is a set of APIs included in the framework 4, please visit this link for more information: here.

We also use the class Action, that encapsulates a method. It's very useful in this case to encapsulate the callback methods without having to declare them as class fields. To learn more about this class, please visit this link: here.

As the worker is running async, the worker implements some events to send back information. 

First step: Creating a helper managing the invoke method

The basis of all guidelines is to not develop a process twice: when you have to manage cross threads controls access for multiple controls in your code, you should have the pattern implemented once.

To do so, we use a helper providing a method that manages control access and callback method firing:

public static class ControlThreadingHelper
{
    public static void InvokeControlAction<t>(t control, Action action) where t : Control
    {
        if (control.InvokeRequired)
            control.Invoke(new Action<t, Action>(InvokeControlAction), new object[] { control, action });
        else
            action();
    }
}

This helper is fully reusable for all controls thanks to generics: it checks the InvokeRequired property and fires the callback method embedded in an Action. The class Action can be assigned by a lambda expression, so it's very simple to write code.  

Thanks to this helper, we can now manage all controls access, cross threads or not, by a unique way:

private void AppendLogText(string logText)
{
    ControlThreadingHelper.InvokeControlAction(tbLog, () =>
    {
        if (!string.IsNullOrEmpty(tbLog.Text))
            tbLog.AppendText(Environment.NewLine);
        tbLog.AppendText(string.Concat(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"), " : ", logText));
    });
}

Second step: Simplifying code writing 

To have simplified code writing, we should implement the control access method directly in the class Control.

We can do this thanks to an extension method: 

public static class ControlThreadingExtensions
{
    public static void Invoke<t>(this t control, Action action) where t : Control
    {
        ControlThreadingHelper.InvokeControlAction<t>(control, action);
    }
}

This extension method allows us to implement control access directly onto the controls of our WinForm:

private void AppendLogText(string logText)
{
    tbLog.Invoke(() =>
    {
        if (!string.IsNullOrEmpty(tbLog.Text))
            tbLog.AppendText(Environment.NewLine);
        tbLog.AppendText(string.Concat(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"), " : ", logText));
    });
}

We have separated the concerns: cross threads accesses are managed by a unique method in the helper while specific form behaviour is assigned into the form behind code.

Points of interest  

In this article, we have seen how coupling the Action class, helpers, and extension methods have helpes us write methods that provide easy-to-use cross-threads controls access methods.

History 

  • 19/06/2012: Bugfix : use an empty Action instead of an Action<t> for callback method 
  • 19/06/2012: Original version. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Peltchag
Software Developer
France France
No Biography provided

Comments and Discussions

 
QuestionDownload of source doesn't work in IE and Chrome PinmemberTN_DK29-Jan-14 11:31 
AnswerRe: Download of source doesn't work in IE and Chrome PinmemberPeltchag30-Jan-14 5:12 
SuggestionIt has already be made in 2009 PinmemberCarlos190719-Jun-12 7:36 
GeneralRe: It has already be made in 2009 PinmemberPeltchag19-Jun-12 21:57 
GeneralRe: It has already be made in 2009 PinmemberCarlos190720-Jun-12 1:19 
GeneralRe: It has already be made in 2009 PinmemberPeltchag20-Jun-12 6:21 
GeneralMy vote of 3 PinmvpPaulo Zemek19-Jun-12 5:50 
GeneralRe: My vote of 3 PinmemberPeltchag19-Jun-12 6:14 
GeneralRe: My vote of 3 PinmvpPaulo Zemek19-Jun-12 6:24 
GeneralRe: My vote of 3 PinmemberPeltchag19-Jun-12 6:54 
QuestionNice idea but this has already been done for you in the .NET Framework PinmvpSacha Barber19-Jun-12 4:03 
AnswerRe: Nice idea but this has already been done for you in the .NET Framework PinmvpPaulo Zemek19-Jun-12 5:48 
AnswerRe: Nice idea but this has already been done for you in the .NET Framework PinmemberPeltchag19-Jun-12 6:20 
GeneralMy vote of 5 Pinmemberkosmoh19-Jun-12 3:26 
GeneralRe: My vote of 5 PinmemberPeltchag19-Jun-12 6:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141216.1 | Last Updated 29 Jan 2014
Article Copyright 2012 by Peltchag
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid