title: Is it appropriate to extend Control to provide consistently safe Invoke/BeginInvoke functionality?
body: <p>In the course of my maintenance for an older application that badly violated the cross-thread update rules in winforms, I created the following extension method as a way to quickly fix illegal calls when I've discovered them:</p>
  
  <pre><code>/// &lt;summary&gt;
  /// Execute a method on the control's owning thread.
  /// &lt;/summary&gt;
  /// &lt;param name="uiElement"&gt;The control that is being updated.&lt;/param&gt;
  /// &lt;param name="updater"&gt;The method that updates uiElement.&lt;/param&gt;
  /// &lt;param name="forceSynchronous"&gt;True to force synchronous execution of 
  /// updater.  False to allow asynchronous execution if the call is marshalled
  /// from a non-GUI thread.  If the method is called on the GUI thread,
  /// execution is always synchronous.&lt;/param&gt;
  public static void SafeInvoke(this Control uiElement, Action updater, bool forceSynchronous)
  {
      if (uiElement == null)
      {
          throw new ArgumentNullException("uiElement");
      }
  
      if (uiElement.InvokeRequired)
      {
          if (forceSynchronous)
          {
              uiElement.Invoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
          }
          else
          {
              uiElement.BeginInvoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
          }
      }
      else
      {
          if (!uiElement.IsHandleCreated)
          {
              // Do nothing if the handle isn't created already.  The user's responsible
              // for ensuring that the handle they give us exists.
              return;
          }
  
          if (uiElement.IsDisposed)
          {
              throw new ObjectDisposedException("Control is already disposed.");
          }
  
          updater();
      }
  }
  </code></pre>
  
  <p>Sample usage:</p>
  
  <pre><code>this.lblTimeDisplay.SafeInvoke(() =&gt; this.lblTimeDisplay.Text = this.task.Duration.ToString(), false);
  </code></pre>
  
  <p>I like how I can leverage closures to read, also, though forceSynchronous needs to be true in that case:</p>
  
  <pre><code>string taskName = string.Empty;
  this.txtTaskName.SafeInvoke(() =&gt; taskName = this.txtTaskName.Text, true);
  </code></pre>
  
  <p>I don't question the usefulness of this method for fixing up illegal calls in legacy code, but what about new code?  </p>
  
  <p>Is it good design to use this method to update UI in a piece of new software when you may not know what thread is attempting to update the ui, or should new Winforms code generally contain a specific, dedicated method with the appropriate <code>Invoke()</code>-related plumbing for all such UI updates?  (I'll try to use the other appropriate background processing techniques first, of course, e.g. BackgroundWorker.)</p>
  
  <p>Interestingly this won't work for <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripitem.aspx" rel="noreferrer">ToolStripItems</a>.  I just recently discovered that they derive directly from <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.component.aspx" rel="noreferrer">Component</a> instead of from <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.control.aspx" rel="noreferrer">Control</a>.  Instead, the containing <code>ToolStrip</code>'s invoke should be used.</p>
  
  <h2>Followup to comments:</h2>
  
  <p>Some comments suggest that:</p>
  
  <pre><code>if (uiElement.InvokeRequired)
  </code></pre>
  
  <p>should be:</p>
  
  <pre><code>if (uiElement.InvokeRequired &amp;&amp; uiElement.IsHandleCreated)
  </code></pre>
  
  <p>Consider the following <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx" rel="noreferrer">msdn documentation</a>:</p>
  
  <blockquote>
    <p>This means that InvokeRequired can
    <strong>return false</strong> if Invoke is not required
    (the call occurs on the same thread),
    or <strong>if the control was created on a
    different thread but the control's
    handle has not yet been created.</strong></p>
    
    <p>In the case where the control's handle
    has not yet been created, you should
    not simply call properties, methods,
    or events on the control. This might
    cause the control's handle to be
    created on the background thread,
    isolating the control on a thread
    without a message pump and making the
    application unstable.</p>
    
    <p><strong>You can protect against this case by
    also checking the value of
    IsHandleCreated when InvokeRequired
    returns false on a background thread.</strong></p>
  </blockquote>
  
  <p>If the control was created on a different thread but the control's handle has not yet been created, <code>InvokeRequired</code> returns false.  This means that if <code>InvokeRequired</code> returns <code>true</code>, <code>IsHandleCreated</code> will always be true.  Testing it again is redundant and incorrect.</p>