Click here to Skip to main content
15,881,248 members
Articles / General Programming / Threads

How To: Manage cross-thread WinForms controls access

Rate me:
Please Sign up or sign in to vote.
4.40/5 (9 votes)
29 Jan 2014CPOL2 min read 44.9K   373   27   15
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:

C#
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:

C#
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:

C#
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: 

C#
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:

C#
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)


Written By
Software Developer
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionDownload of source doesn't work in IE and Chrome Pin
TN_DK29-Jan-14 10:31
TN_DK29-Jan-14 10:31 
AnswerRe: Download of source doesn't work in IE and Chrome Pin
Peltchag30-Jan-14 4:12
Peltchag30-Jan-14 4:12 
SuggestionIt has already be made in 2009 Pin
Carlos190719-Jun-12 6:36
professionalCarlos190719-Jun-12 6:36 
GeneralRe: It has already be made in 2009 Pin
Peltchag19-Jun-12 20:57
Peltchag19-Jun-12 20:57 
GeneralRe: It has already be made in 2009 Pin
Carlos190720-Jun-12 0:19
professionalCarlos190720-Jun-12 0:19 
GeneralRe: It has already be made in 2009 Pin
Peltchag20-Jun-12 5:21
Peltchag20-Jun-12 5:21 
GeneralMy vote of 3 Pin
Paulo Zemek19-Jun-12 4:50
mvaPaulo Zemek19-Jun-12 4:50 
GeneralRe: My vote of 3 Pin
Peltchag19-Jun-12 5:14
Peltchag19-Jun-12 5:14 
GeneralRe: My vote of 3 Pin
Paulo Zemek19-Jun-12 5:24
mvaPaulo Zemek19-Jun-12 5:24 
GeneralRe: My vote of 3 Pin
Peltchag19-Jun-12 5:54
Peltchag19-Jun-12 5:54 
QuestionNice idea but this has already been done for you in the .NET Framework Pin
Sacha Barber19-Jun-12 3:03
Sacha Barber19-Jun-12 3:03 
AnswerRe: Nice idea but this has already been done for you in the .NET Framework Pin
Paulo Zemek19-Jun-12 4:48
mvaPaulo Zemek19-Jun-12 4:48 
AnswerRe: Nice idea but this has already been done for you in the .NET Framework Pin
Peltchag19-Jun-12 5:20
Peltchag19-Jun-12 5:20 
GeneralMy vote of 5 Pin
kosmoh19-Jun-12 2:26
kosmoh19-Jun-12 2:26 
GeneralRe: My vote of 5 Pin
Peltchag19-Jun-12 5:24
Peltchag19-Jun-12 5:24 

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

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