views:

55

answers:

1

I've been working support for a while on a legacy application and I've noticed a bit of a problem. The system is an incredibly complex client/server with standard and custom frameworks.

One of the custom frameworks built into the application involves validating workflow actions. It finds potential errors, separates them into warnings and errors, and passes the results back to the client. The main difference between warnings and errors is that warnings ask the user if they wish to ignore the error.

The issue I have is that the dialog for this prompt is created on a non-ui thread, and thus we get cross-threading issues when the dialog is shown. I have attempted to invoke the showing of the dialog, however this fails because the window handle has not been created. (InvokeRequired returns false, which I assume in this case means it cannot find a decent handle in its parent tree, rather than that it doesn't require it.)

Does anyone have any suggestions for how I can create this dialog and get the UI thread to set it up and call it?

+1  A: 

Hi,

I am not entirely clear on the details of your implementation but the below code is how you would handle marshalling a call from you're non-ui thread to the ui thread. This code snippet assumes that the "this" object is a windows form and represents the ui thread.

The idea is that your non-ui thread calls the method named "ShowMessageBox", which resides on the ui-thread. When the call happens you check the this.InvokeRequired from an object on the ui-thread, which in this example would be a windows form. The InvokeRequired would return "true" which would cause the code in the first part of the if statement to be executed. This code invokes a call back to the ShowMessageBox function from the main ui-thread by creating a delegate of the same signature as the "ShowMessageBox" method and re-passing the sender object and event args, in effect marshalling the non-ui thread call to the ui-thread. This subsequent call to the “ShowMessageBox” method is now "marshaled" to the ui-thread and will bypass the first part of the if and move to the else where you can call the messagebox or form or whatever you need to.

Enjoy!

private object _lock = new object(); //should have class scope

private void ShowMessageBox(object sender, EventArgs e)
{
  if (this.InvokeRequired)
  {
    lock (_lock)
    {
      EventHandler d = new EventHandler(ShowMessageBox);
      this.Invoke(d, new object[] { sender, e });
      return;
    }
  }
  else
  {
    MessageBox.Show("Show some messsage or invoke your form instance.");
  }
}
Doug
This doesn't work in this situation, as I mentioned above. Without a window handle, you cannot call invoke.
Frater
Have you considered the above pattern and creating a custom EventArgs class that would pass a message or enum type that you could then use to create the appropriate instance of the form from within the else part of the if statement. This would avoid your issue of creating the form on a non ui thread. You would only be passing some sort of type indicator or message and then acting on that message from the ui-thread instead of trying to invoke a form instance from a thread other than the one it was created on.
Doug
That might be worth a shot, though it'd be pretty complicated. The code is fairly horrific. I'll give it some more thought, thanks.
Frater