J'ai eu le même problème et j'ai implémenté le comportement du dialogue modal comme décrit dans ce post : http://social.msdn.microsoft.com/Forums/vstudio/en-US/820bf10f-3eaf-43a8-b5ef-b83b2394342c/windowsshowmodal-to-parentowner-window-only-not-entire-application?forum=wpf
J'ai également essayé une approche à threads multiples, mais cela a causé des problèmes avec les bibliothèques tierces (caliburn micro & telerik wpf controls), puisqu'elles ne sont pas construites pour être utilisées dans des threads multiples. Il est possible de les faire fonctionner avec plusieurs threads UI, mais je préfère une solution plus simple...
Si vous implémentez le dialogue comme décrit, vous ne pouvez plus utiliser la propriété DialogResult, car cela provoquerait une exception "DialogResult ne peut être défini qu'après la création de la fenêtre et son affichage en tant que dialogue". Implémentez simplement votre propre propriété et utilisez-la à la place.
Vous avez besoin de la référence suivante de l'API Windows :
/// <summary>
/// Enables or disables mouse and keyboard input to the specified window or control.
/// When input is disabled, the window does not receive input such as mouse clicks and key presses.
/// When input is enabled, the window receives all input.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="bEnable"></param>
/// <returns></returns>
[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hWnd, bool bEnable);
Alors utilisez ceci :
// get parent window handle
IntPtr parentHandle = (new WindowInteropHelper(window.Owner)).Handle;
// disable parent window
EnableWindow(parentHandle, false);
// when the dialog is closing we want to re-enable the parent
window.Closing += SpecialDialogWindow_Closing;
// wait for the dialog window to be closed
new ShowAndWaitHelper(window).ShowAndWait();
window.Owner.Activate();
Il s'agit du gestionnaire d'événement qui réactive la fenêtre parent, lorsque le dialogue est fermé :
private void SpecialDialogWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
var win = (Window)sender;
win.Closing -= SpecialDialogWindow_Closing;
IntPtr winHandle = (new WindowInteropHelper(win)).Handle;
EnableWindow(winHandle, false);
if (win.Owner != null)
{
IntPtr parentHandle = (new WindowInteropHelper(win.Owner)).Handle;
// reenable parent window
EnableWindow(parentHandle, true);
}
}
Et voici le ShowAndWaitHelper nécessaire pour obtenir le comportement de dialogue modal (il bloque l'exécution du thread, mais exécute toujours la boucle de messages.
private sealed class ShowAndWaitHelper
{
private readonly Window _window;
private DispatcherFrame _dispatcherFrame;
internal ShowAndWaitHelper(Window window)
{
if (window == null)
{
throw new ArgumentNullException("window");
}
_window = window;
}
internal void ShowAndWait()
{
if (_dispatcherFrame != null)
{
throw new InvalidOperationException("Cannot call ShowAndWait while waiting for a previous call to ShowAndWait to return.");
}
_window.Closed += OnWindowClosed;
_window.Show();
_dispatcherFrame = new DispatcherFrame();
Dispatcher.PushFrame(_dispatcherFrame);
}
private void OnWindowClosed(object source, EventArgs eventArgs)
{
if (_dispatcherFrame == null)
{
return;
}
_window.Closed -= OnWindowClosed;
_dispatcherFrame.Continue = false;
_dispatcherFrame = null;
}
}