Ho avuto lo stesso problema e implementato il comportamento finestra di dialogo modale come descritto in questo 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
Ho anche provato un approccio più thread UI, ma questo ha causato problemi con le librerie di terze parti (Caliburn micro & Telerik wpf controls), poiché non sono progettati per essere utilizzati in più thread dell'interfaccia utente. È possibile farli funzionare con più thread dell'interfaccia utente, ma preferisco una soluzione più semplice ...
Se si implementa la finestra di dialogo come descritto, non è più possibile utilizzare la proprietà DialogResult, poiché causerebbe un "DialogResult può essere impostato solo dopo aver creato Finestra e visualizzato come finestra di dialogo "eccezione. Basta implementare la tua proprietà e usarla al suo posto.
sono necessari i seguenti finestre API di riferimento:
/// <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);
quindi utilizzare questo:
// 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();
Questo è il gestore di eventi che riabilita la finestra padre, quando la finestra è chiusa:
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);
}
}
E questo è lo ShowAndWaitHelper necessario per ottenere il comportamento del dialogo modale (questo blocca l'esecuzione del thread, ma esegue ancora il loop dei messaggi.
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;
}
}
La tua risposta è stata incredibilmente utile. Ho creato una versione del metodo di estensione async Task ShowDialogAsync' di questo. –
jnm2