views:

2505

answers:

6

I want to call ShowDialog() when a keyboard hook event is triggered but I'm having some difficulties:

  • ShowDialog() blocks so I can't call it from the hook triggered event because it will block the OS.
  • I can start a new thread and call ShowDialog() from there, but I get some nasty exception. I guess I can't call ShowDialog() in any other thread.
  • I can start a timer: in the next 50 milliseconds call ShowDialog() (which is a nasty hack btw and I rather no do this) But then the timer fires in a new thread and I get then I run into the same problem explained in the previous bullet

I'm sure there must be a way.

+1  A: 

I'm not sure about ShowDialog, but whenever you get an exception when trying to do something with the UI in a background thread, it means you should use the UI dispatcher.

Try calling the BeginInvoke method (if you are on Windows Forms) of any UI object you control with a delegate that calls the showdialog.

Also, make sure to try (before this) passing a reference to a valid owner in the show dialog method.

Santiago Palladino
A: 

Without the "nasty exception" its hard to tell what's going on. I would assume its because your thread isn't an STA thread, and the UI objects are throwing the exception when they get instantiated. Set your new thread's apartment model to be STA instead of MTA and see if that helps.

And if you don't know what the difference is, you should do some reading up.

Will
+2  A: 

The problem may be that you are trying to put UI in a non-ui thread.

Make your event fire from another thread and invoke the method that runs ShowDialog() from your UI thread.

Essentially you want to keep your UI on the UI thread and move anything else to a back ground thread.

Check out Gekki Software for some details (there are zillions of others - This just happens to be the first one I found in research archives).

Brody
A: 

ShowDialog() will block your application's thread, but that's what it's supposed to do. If you don't want the form blocking your application, call Show() instead.

ShowDialog() will not "block the OS", so don't be reluctant to use it.

MusiGenesis
It will block the OS because it's inside an OS-wide keyboard hook.
Judah Himango
This may be a semantic problem, but huh? The entire OS is blocked on a keyboard hook?
MusiGenesis
Sorry, "the OS" may be overstating it. The OS-wide keyboard input would be blocked. In other words, you won't be able to enter text anywhere else. (Haven't tested this theory, but I believe that's what will happen.)
Judah Himango
I see what you're saying. When you show a form modally in .NET using the form's ShowDialog method, the form is only modal to the application, not to the OS. You can still go to some other application and type.
MusiGenesis
As always with StackOverflow, I have no idea why my answer was down-voted (twice).
MusiGenesis
A: 

You really should be able to show the dialog from a KeyPress type event. can we see your code?

Also, if you use ShowDialog() froim another thread, it will not be modal (no parent). It would be the same as using Show().

Ed Swangren
A: 

Try this:

void MyKeyboardHookHandler(...)
{
     WindowsFormsSynchronizationContext.Current.Post(state =>
     {
         Form f = new Form();
         f.ShowDialog();
     }, null);
}
Judah Himango
Spooky, how does this work? Whats really going to happen in the background? A referral will also do :)
Haim Bender
What's happening is that it posts a special message to your WIN32 message pump. When WinForms encounters that message, it executes the function you passed in there.It's the same thing as someControl.BeginInvoke, but in a more reusable fashion (WPF uses SyncContexts too!)
Judah Himango