Tuesday, April 07, 2009

MethodInvoker: Invoking a control from a worker thread

Invoking a control from a worker thread is common when you're doing multithreading in a windows form. The usual pattern for this goes something like:

private delegate void PrettyMuchUselessDelegate(string text);

private void WorkerMethod() {
  string result;
  // perform some excruciating calculations here to fill the variable 'result'
  UpdateUI(result);
}


private void UpdateUI(string text) {
  if(lblResult.InvokeRequired) {
    lblResult.Invoke(new PrettyMuchUselessDelegate(UpdateUI),new object[] { text }));
  } else {
    lblResult.Text = text;
  }
}

Lots of code to do one simple thing: lblResult.Text = text. But by using tools available to us in the framework and the C# compiler, we can compress this down to:

private void WorkerMethod() {
  string result;
  // perform some excruciating calculations here to fill the variable 'result'
  lblResult.Invoke(new MethodInvoker(delegate { lblResult.Text = result; }));
}


Because we know WorkerMethod is running on a worker thread, we don't bother checking InvokeRequired. We can directly call Invoke on our control, passing a new delegate of type System.Windows.Forms.MethodInvoker. MethodInvoker is a delegate for a method that takes no parameters and returns void. Instead of creating a separate method to invoke, we pass in an anonymous method that sets the text of the label. Using MethodInvoker and anonymous methods helps make the code simpler and more elegant, and what's more important than that?

No comments: