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

Avoiding InvokeRequired

By , 27 Apr 2012
 

Introduction

This minor article is an enhancement to the excellent piece of work by Pablo Grisafi.  The goal is to enhance Pablo's code to work in cases where controls are not all created on the same (usually "UI") thread. 

Using the code  

The enhancement is relatively minor and virtually everyone with enough understanding of delegates and generics could easily enhance Pablo's version as I did below.  While Pablo's version works for 95+% cases, in very special circumstances, a control might need to be created on another thread, thus requiring InvokeRequired check on that control's property -- not on the form's.  The idea behind these enhancements is to allow the extension method to handle this type of scenario.  

The code below helps ensure that all controls are updated on the thread on which they were created even when they were created on different threads.  

static class ControlExtensions
{
  public static void InvokeOnOwnerThread<T>(this T control, Action<T> invoker) where T : Control
  {
    if (control.InvokeRequired)
      control.Invoke(invoker, control);
    else
      invoker(control);
  }
}  

The code that uses this extension method would look like this: 

private void UpdateFormTextFromSomeThread(string message)
{
  this.InvokeOnOwnerThread((form) => form.Text = message);  
}

History

No changes. 

License

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

About the Author

Igor Pashchuk, MBA
Software Developer (Senior) Credit Suisse
United States United States
Member
I was introduced to computer programming at the age of 12 although I did not become particularly interested in software development until I turned 19 when I used one of my electives to take a computer science class. Since then, I never stopped writing software. My current interests are .NET, patterns and practices, and agile development (TDD and BDD).

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionConverting it to vb.netmemberpilouk4 Oct '12 - 4:56 
i have a little problem converting your method to vb.net can u help me ?
AnswerRe: Converting it to vb.netmemberIgor Pashchuk, MBA12 Oct '12 - 13:04 
Hi, my VB.NET is a bit rusty: I haven't written anything in VB.NET since generics and lambdas were introduced. Have you tried http://www.developerfusion.com/tools/convert/csharp-to-vb/[^]? I used it quite a few times to convert C# to VB.NET back in the days when I was writing apps in VB.NET.
AnswerRe: Converting it to vb.net [modified]membersage4530 Nov '12 - 6:33 
A comparable VB.NET version would be written something like:
 
Module InvokeRequiredHandler
    ''' <summary>
    ''' Provides a thread-safe call to form elements/controls. [Templated Method]
    ''' </summary>
    ''' <param name="controlToInvoke">(As T) Name of the form element/control to invoke.</param>
    ''' <param name="actionToPerform">(As Action(Of T)) Action to perform on the form element.</param>
    ''' <remarks>Example Usage:
    ''' <c>Public SomeElement As SomeControl</c>
    ''' <c>Private SomeElement2 As SomeControl</c>
    ''' <c>SomeElement.HandleInvokeRequired(Sub(SomeElement As SomeControl) SomeElement.Text = "Text Here")</c>
    ''' <c>SomeElement2.HandleInvokeRequired(Sub(SomeElement2 As SomeControl) SomeElement2.Enabled = False)</c>
    ''' </remarks>
    <System.Runtime.CompilerServices.Extension()> _
    Public Sub HandleInvokeRequired(Of T As {Control, ISynchronizeInvoke}) _
        (ByVal controlToInvoke As T, ByVal actionToPerform As Action(Of T))
        'Check to see if the control's InvokeRequired property is true
        If controlToInvoke.InvokeRequired Then
            'Use Invoke() to invoke your action
            controlToInvoke.Invoke(actionToPerform, New Object() {controlToInvoke})
        Else
            'Check to ensure the control's handle is created
            If Not controlToInvoke.IsHandleCreated Then
                Return
            End If
 
            'Check to ensure the control has not been disposed
            If controlToInvoke.IsDisposed Then
                Throw New ObjectDisposedException(String.Format("{0} is disposed.", controlToInvoke))
            End If
 
            'Perform the action
            actionToPerform(controlToInvoke)
        End If
    End Sub
End Module
 
I have observed, though, that a race condition exists between the Disposed check and actually updating the control. When dealing with thread's, you have to keep in mind the fact that your thread may make an initial call to a undisposed control, but when the thread recieves priority again and makes the call to update the control, that the control could have been disposed by some other method. It's probably why most people would recommend using a background worker and updating the UI using the ProgressChanged event.
 
HTH,
 
-saige-

modified 30 Nov '12 - 12:39.

SuggestionInstantiating UI objects on a non-UI threadmemberMember 34676551 Jun '12 - 10:09 
I've run into this issue by accident. I honestly can't think of a good reason to create a UI object on a non-UI thread. Can you suggest a scenario where this would be desired?
GeneralRe: Instantiating UI objects on a non-UI threadmemberIgor Pashchuk, MBA1 Jun '12 - 16:30 
Generally, I would say: "Don't do it!". Creating controls on non-UI threads introduces major risks. Only those who understand the risks should even consider the approach. Even then, there are probably better ways because Windows forms and cross-threading just don't get along Smile | :) .
 
I haven't come across the scenario myself but have heard David Platt[^] mention a case whereby the form (or some control) was constantly updated from other threads, which worked OK until the user dragged the window, causing updates to be missed. I don't know the full details though...
 
I'm not sure if the following scenario truly warrants the approach the user is trying, but it is a good example of using the snippet I provided: http://stackoverflow.com/questions/2250749/add-a-control-on-a-form-from-another-thread[^]

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 27 Apr 2012
Article Copyright 2012 by Igor Pashchuk, MBA
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid