BeginInvoke

Cross-thread data access

Continuing on my recent asynchronous UI adventures, my background object tried to access the SelectedItem of a ComboBox and I came crashing down with the dreaded Cross-Thread exception. At this point most of my code has the if(InvokeRequired) boilerplate down….

And every time i cut-and-paste that snippet and tweak if for the current method, I again wonder why the UI framework can’t do some Auto-Invoking magic. But I digress.

…The scenario this time was one of data access to the plain, call BeginInvoke and return approach didn’t apply. This was a scenario I hadn’t yet seen. Unlike normal delegate BeginInvoke, you don’t provide a callback for the EndInvoke. Control.BeginInvoke works differently, but really, it also works simpler. It’s just that it’s not really pointed out on MSDN how the Begin and End fit together in the scope of a Control. The other issue was that I was accessing a property, so there wasn’t a simple delegate for invoking it. Instead I created a simple wrapper Accessor Method for ComboBoxen:

public delegate object GetSelectedItemDelegate(ComboBox control);

public object GetSelectedItem(ComboBox control)
{
  if (this.InvokeRequired)
  {
    IAsyncResult ar = BeginInvoke(new GetSelectedItemDelegate(GetSelectedItem), control);
    return EndInvoke(ar);
  }
  return control.SelectedItem;
}

It’s always the Invoke

If you are working on the .NET Compact Framework 1.0 and you get an ArgumentException trying to manipulate your UI (such as adding a Control to a form), you are likely doing this operation from a thread other than you UI thread and should be using Invoke. Thanks to jonfroelich‘s post “Controls.Add ArgumentException” for putting me on the right path. With all my frustrating debugging and unexplained freezes, i’d completely forgot that the particular code branch I was looking at was initiated by a callback from a WorkerThread.

Of course the Invoke facilities of .NETCF 1.0 are pitiful, lacking the things that make this whole single-threaded UI business bearable in regular Windows.Forms. There is not InvokeRequired for one thing, nor is there BeginInvoke. And even Invoke just provides the Invoke(Delegate) signature, not the much more useful Invoke(Delegate, Object[]).

Add to that that the only valid Delegate is an EventHandler, which takes two arguments, the exclusion of Invoke(Delegate, Object[]) really is painful.

By arne on | .net | A comment?
Tags: ,

Invoke vs. BeginInvoke

Been using the DebugLog code a bunch but kept having the occasional lock-up at shutdown. So i went back to the whole Invoke business. Problem is that while Invoke does make sure our update code runs on the proper thread, it is also synchronous, which means that if you are asking the DebugLog worker to Join and it is just then calling Invoke, you’ve got yourself a deadlock. The thread asking for the Join is now blocked, but it’s also the thread responsible for the handling the Invoke. Solution:Should’ve used BeginInvoke, since it does the call asynchronously, avoiding the the Deadlock issue.

The updated .cs and .resx files are here

As I was typing this, suddenly the room shook as if a truck had hit the house. Turns out there was a 5.6 Earthquake near Anza, CA, about 60 miles away.

By arne on | .net | A comment?
Tags: