Microsoft Developer Network >
Forenhomepage
>
Windows Presentation Foundation (WPF)
>
Modal dialog / native parent focus problems
Modal dialog / native parent focus problems
- Background:
I am writing a managed add-in for a third-party application. The application is written in C++/ATL, and exposes a COM interface for add-ins. My add-in responds to various events from the application, and occasionally needs to display a modal dialog to the user.
Events on the interface a fired from an MTA thread, so when I need to display any UI I have to marshal the call to an STA thread. Also, since I can't use Application.Run, I have to ensure that the thread has a running Dispatcher. This all appears to work.
The application exposes its main window handle as a simple Int32 property. I am using the WindowInteropHelper class to assign this as the parent of the modal dialog before calling ShowDialog.
Problem 1:
When the modal dialog contains a ComboBox, and the user expands the drop-down list, the dialog disappears, but the drop-down list popup remains visible. Clicking on the area where the dialog should be usually brings it back. To avoid this problem, I have set the Topmost property of my dialog to true. It's not a perfect solution, but it solves the immediate problem.
Problem 2:
When the modal dialog displays a FileDialog (OpenFileDialog or SaveFileDialog, either the WPF or WinForms versions), when the dialog is dismissed the main application window loses focus and is hidden behind a random window. Usually it seems to be the window which was active when the application launched, but it could be any other window which is open. As a workaround, I can call SetForegroundWindow when my dialog closes, passing in the handle of the application window, but the user still sees an ugly flash of the other window.
Strangely, a simple WinForms add-in using ShowDialog with an IWin32Window wrapper for the application doesn't seem to suffer from the same problems. However, having learnt WPF, I don't want to go back!
I'm hoping that there's something obvious I've forgotten to do, or that someone with a working knowledge of Windows modal message loops can point me in the right direction.
Thanks,
Richard
Antworten
EnableWindow seems to fix problem 1 - the ComboBox popup now works without setting the Topmost property to true. However, now the application window loses focus every time a dialog is closed, whether or not I've shown a file dialog.
Thanks,
Richard
Then is it possible to bring the main window back to focus by using the SetActiveWindow function (need to make use of AttachThreadInput if calling from the add-in's thread though)?
Regards,
Jie
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
If you have any feedback, please tell us.
The CodeFx Project
My Blog (in Simplified Chinese)- Als Antwort markiertrichard_deeming Mittwoch, 4. November 2009 17:54
Alle Antworten
- Hi Richard,
Is your WPF dialog running on the very same thread that also owns the application main window?
Thanks,
Jie
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
If you have any feedback, please tell us.
The CodeFx Project
My Blog (in Simplified Chinese) - Jie,
Unfortunately not - the main application is running on an MTA thread, which WPF doesn't like. I have to start a new STA thread with a Dispatcher when the application starts up, and then use Invoke to run the code which displays the dialog box. I did try starting a new thread each time, but WPF didn't like that - the second time I tried to show a dialog, I got a nasty exception from the framework.
Thanks,
Richard Jie,
Unfortunately not - the main application is running on an MTA thread, which WPF doesn't like. I have to start a new STA thread with a Dispatcher when the application starts up, and then use Invoke to run the code which displays the dialog box. I did try starting a new thread each time, but WPF didn't like that - the second time I tried to show a dialog, I got a nasty exception from the framework.
Thanks,
Richard
Then I'm afraid in this case things just won't work nicely. I'm not 100% sure, but from the code of the Window.ShowDialog() method (you can view it via Reflector), we can see that this method is expected to work with other windows on a very same thread. For example, it calls GetActiveWindow function to record the previous active window before the modal dialog is shown, while this function only retrieves the window handle to the active window attached to the calling thread's message queue. So in your case, it just won't recognize your main window as the previous active window. And that could cause the following weirdness.
Windows Forms uses a different message loop. If WinForm works with your application as you expected, you can consider use a WinForm as the host window and put your WPF controls in it. That could solve the modal problem. Otherwise, you'll probably have to live with the current workarounds.
My two cents.
Regards,
Jie
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
If you have any feedback, please tell us.
The CodeFx Project
My Blog (in Simplified Chinese)- Jie,
Thanks for trying to help. I don't really want to go back to WinForms, as I'd loose a lot of WPF Window functionality (eg: SizeToContent).
Do you think calling AttachThreadInput would make any difference?
On an unrelated note, the ShowDialog method seems to go to a lot of effort to initialize the _dialogOwnerHandle, which doesn't appear to be used anywhere. Do you know if there's a reason for this, or if it's a mistake?
Thanks,
Richard Jie,
Thanks for trying to help. I don't really want to go back to WinForms, as I'd loose a lot of WPF Window functionality (eg: SizeToContent).
Do you think calling AttachThreadInput would make any difference?
On an unrelated note, the ShowDialog method seems to go to a lot of effort to initialize the _dialogOwnerHandle, which doesn't appear to be used anywhere. Do you know if there's a reason for this, or if it's a mistake?
Thanks,
Richard
Richard,
Can you try call EnableWindow to disable the owner window before calling ShowDialog?
Something like:
Regards,try { EnableWindow(hWndOwner, false); dlg.ShowDialog(); } finally { EnableWindow(hWndOwner, true); }
Jie
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
If you have any feedback, please tell us.
The CodeFx Project
My Blog (in Simplified Chinese)- EnableWindow seems to fix problem 1 - the ComboBox popup now works without setting the Topmost property to true. However, now the application window loses focus every time a dialog is closed, whether or not I've shown a file dialog.
Thanks,
Richard EnableWindow seems to fix problem 1 - the ComboBox popup now works without setting the Topmost property to true. However, now the application window loses focus every time a dialog is closed, whether or not I've shown a file dialog.
Thanks,
Richard
Then is it possible to bring the main window back to focus by using the SetActiveWindow function (need to make use of AttachThreadInput if calling from the add-in's thread though)?
Regards,
Jie
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
If you have any feedback, please tell us.
The CodeFx Project
My Blog (in Simplified Chinese)- Als Antwort markiertrichard_deeming Mittwoch, 4. November 2009 17:54
- Success!
Calling AttachThreadInput (with idAttach = main window thread and idAttachTo = dialog window thread) seems to fix the focus issue without needing to call SetActiveWindow.
Many thanks for all your help.
Regards,
Richard

