Microsoft Developer Network > Forenhomepage > Windows Presentation Foundation (WPF) > Modal dialog / native parent focus problems
Stellen Sie eine FrageStellen Sie eine Frage
 

BeantwortetModal dialog / native parent focus problems

  • Freitag, 16. Oktober 2009 19:00richard_deeming TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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

  • Donnerstag, 29. Oktober 2009 11:10Wang, JieMSFT, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Beantwortet
    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)

Alle Antworten

  • Montag, 19. Oktober 2009 11:00Wang, JieMSFT, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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)
  • Montag, 19. Oktober 2009 11:19richard_deeming TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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
  • Dienstag, 20. Oktober 2009 12:50Wang, JieMSFT, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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)
  • Dienstag, 20. Oktober 2009 15:02richard_deeming TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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
  • Montag, 26. Oktober 2009 11:46Wang, JieMSFT, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Enthält Code
    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:

    try
    {
        EnableWindow(hWndOwner, false);
        dlg.ShowDialog();
    }
    finally
    {
        EnableWindow(hWndOwner, true);
    }
    
    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)
  • Montag, 26. Oktober 2009 16:15richard_deeming TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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
  • Donnerstag, 29. Oktober 2009 11:10Wang, JieMSFT, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Beantwortet
    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)
  • Mittwoch, 4. November 2009 17:56richard_deeming TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    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