Click here to Skip to main content
15,883,870 members
Articles / Programming Languages / C# 4.0

Updating Your Form from Another Thread without Creating Delegates for Every Type of Update

Rate me:
Please Sign up or sign in to vote.
4.85/5 (85 votes)
8 Oct 2010CPOL1 min read 283.2K   5.4K   242   59
Updating your form from another thread without creating delegates for every type of update

Download SimpleThreadSafeCall.zip - 43.07 KB

Introduction

Threads are nice when you need to do stuff in the background without causing your application to hang. Often you want to show the progress of the load that is being handled. In many occasions, that's a progressbar but in some you want to show in detail what is being done. In the first situation where it is only needed to update a progress bar, a backgroundworker can be used. The background worker sends thread safe events. In that event, you can update your progress bar. In the other situations where you want to show more information of what is being done, you need to call the form from within the other thread. If you do that, you will get an invalid crossthreadcall exception. Many articles that discuss the problem explain how to solve the problem by creating delegates and invoking them.

Example: How to: Make Thread-Safe Calls to Windows Forms Controls

C#
delegate void SetTextCallback(string text);
private void ThreadProcSafe()
{
    // Wait two seconds to simulate some background work
    // being done.
    Thread.Sleep(2000);

    string text = "Written by the background thread.";
    // Check if this method is running on a different thread
    // than the thread that created the control.
    if (this.textBox1.InvokeRequired)
    {
        // It's on a different thread, so use Invoke.
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke
            (d, new object[] { text + " (Invoke)" });
    }
    else
    {
        // It's on the same thread, no need for Invoke
        this.textBox1.Text = text + " (No Invoke)";
    }
}
// This method is passed in to the SetTextCallBack delegate
// to set the Text property of textBox1.
private void SetText(string text)
{
    this.textBox1.Text = text;
} 

I probably don't have to mention this is a lot of code for one simple textbox update.

An easy alternative

Finally, I found a quick and elegant solution to update a form from another thread. Thanks to some great feedback in the comments i was able to futher perfect the implementation.  The code is as follows:

C#
lblProcent.SafeInvoke(d => d.Text = "Written by the background thread");
progressBar1.SafeInvoke(d => d.Value = i);

//or call a methode thread safe. That method is executed on the same thread as the form
this.SafeInvoke(d => d.UpdateFormItems("test1", "test2"));

A threadSafe getter is also available. The getter knows what the return type is, so casting is not necessary.

C#
string textboxtext=textbox.SafeInvoke(d=>d.textbox.text); 

The function SafeInvoke are extension methods.

C#
        public static TResult SafeInvoke<t,>(this T isi, Func<t,> call) where T : ISynchronizeInvoke
        {
            if (isi.InvokeRequired) { 
                IAsyncResult result = isi.BeginInvoke(call, new object[] { isi }); 
                object endResult = isi.EndInvoke(result); return (TResult)endResult; 
            }
            else
                return call(isi);
        }

        public static void SafeInvoke<t>(this T isi, Action<t> call) where T : ISynchronizeInvoke
        {
            if (isi.InvokeRequired) isi.BeginInvoke(call, new object[] { isi });
            else
                call(isi);
        }
</t></t></t,></t,>
I hope this helps

History

  • 17/01/2010 Article published
  • 30/01/2010 Sample project added and article updated with the comments of philippe dykmans
  • 8/10/2010 Sample project changed and article updated with the comments of philippe dykmans  

License

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


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

Comments and Discussions

 
AnswerRe: Why not use Invoke? Pin
jcddcjjcd30-Nov-10 20:11
jcddcjjcd30-Nov-10 20:11 
GeneralMy vote of 10... sorry, 5! Pin
Anthony Daly2-Nov-10 5:00
Anthony Daly2-Nov-10 5:00 
GeneralMy vote of 5 Pin
SohjSolwin12-Oct-10 4:09
SohjSolwin12-Oct-10 4:09 
GeneralMy vote of 5 Pin
Michael Moreno10-Oct-10 22:20
Michael Moreno10-Oct-10 22:20 
GeneralVB Implementation [modified] Pin
NSane7-Oct-10 11:11
NSane7-Oct-10 11:11 
GeneralRe: VB Implementation [modified] Pin
hulinning29-Oct-10 10:37
hulinning29-Oct-10 10:37 
QuestionThank you Sir. Where is your Donate button? Pin
free_p20002-Oct-10 3:04
free_p20002-Oct-10 3:04 
GeneralEven better... i think... Pin
philippe dykmans9-Sep-10 9:08
philippe dykmans9-Sep-10 9:08 
Hello,

Here's a few adaptations to your code i wanted to share.

1) I now hook the extension on ISynchronizeInvoke type, instead of only Control type. This widens its use. After all, this is exactly what the ISynchronizeInvoke interface is made for.

2) The original implementation was only safe in cross-thread situations. So, I added a check on InvokeRequired to make it work in all situations, cross-thread or not...

3) There is not really a need for 2 different method names. Based on the different signatures, the compiler can distinguish which overload to use. So, you can actually cover both 'void' and 'return' cases with just one overloaded method. Which makes it more elegant i think. I.e. eliminates the need for the 'Get' specification.

Here are the adaptations:

First overload covers calls with returns. Example:

Color cl = textBox.SafeInvoke( tbx => tbx.BackColor );
int hash = textBox.SafeInvoke( tbx => tbx.GetHashCode() );

public static TResult SafeInvoke<T, TResult>( this T isi, Func<T, TResult> call )
    where T : ISynchronizeInvoke
{
    if ( isi.InvokeRequired )
    {
        IAsyncResult result = isi.BeginInvoke( call, new object[] { isi } );
        object endResult = isi.EndInvoke( result );
        return (TResult) endResult;
    }

    else
        return call( isi );
}


Second overload covers void calls. Example:

textBox.SafeInvoke( tbx => tbx.BackColor = Color.White );
textBox.SafeInvoke( tbx => tbx.Show() );

public static void SafeInvoke<T>( this T isi, Action<T> call )
    where T : ISynchronizeInvoke
{
    if ( isi.InvokeRequired )
        isi.BeginInvoke( call, new object[] { isi } );

    else
        call( isi );
}


regards,
Philippe
Philippe Dykmans
Software developpement
Advanced Bionics Corp.

GeneralRe: Even better... i think... Pin
Michael Demeersseman9-Sep-10 21:12
Michael Demeersseman9-Sep-10 21:12 
GeneralRe: Even better... i think... Pin
Michael Demeersseman7-Oct-10 21:09
Michael Demeersseman7-Oct-10 21:09 
GeneralRe: Even better... i think... Pin
Kent K29-Mar-13 9:24
professionalKent K29-Mar-13 9:24 
GeneralOutstanding Pin
Thomas Hauff6-Apr-10 16:52
Thomas Hauff6-Apr-10 16:52 
GeneralOne more suggestion Pin
philippe dykmans15-Feb-10 9:30
philippe dykmans15-Feb-10 9:30 
GeneralExcellante! Pin
stixoffire30-Jan-10 12:18
stixoffire30-Jan-10 12:18 
GeneralRe: Excellante! Pin
akyriako7831-Jan-10 22:01
akyriako7831-Jan-10 22:01 
GeneralRe: Excellante! Pin
Sherylee8-Oct-10 0:30
Sherylee8-Oct-10 0:30 
GeneralGood One Pin
SaranRaj 2730-Jan-10 6:56
SaranRaj 2730-Jan-10 6:56 
GeneralPlease make a demo application. Pin
muharrem28-Jan-10 0:05
muharrem28-Jan-10 0:05 
GeneralRe: Please make a demo application. Pin
Michael Demeersseman30-Jan-10 0:40
Michael Demeersseman30-Jan-10 0:40 
QuestionLittle remark on naming Pin
Loic Berthollet25-Jan-10 23:59
Loic Berthollet25-Jan-10 23:59 
AnswerRe: Little remark on naming Pin
Michael Demeersseman30-Jan-10 0:39
Michael Demeersseman30-Jan-10 0:39 
GeneralError : Invalid expression term '=&gt;' Pin
Deagle 0.520-Jan-10 23:15
Deagle 0.520-Jan-10 23:15 
GeneralRe: Error : Invalid expression term '=&gt;' Pin
Michael Demeersseman30-Jan-10 0:31
Michael Demeersseman30-Jan-10 0:31 
GeneralRe: Error : Invalid expression term '=&gt;' Pin
Deagle 0.530-Jan-10 2:58
Deagle 0.530-Jan-10 2:58 
GeneralGood idea, with a small adaptation Pin
philippe dykmans19-Jan-10 6:04
philippe dykmans19-Jan-10 6:04 

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.