ventana modal abrir wpf

modal - abrir ventana wpf c#



La ventana modal de WPF usando ShowDialog() bloquea todas las demás ventanas (2)

Tuve el mismo problema e implementé el comportamiento de diálogo modal como se describe en esta publicación: http://social.msdn.microsoft.com/Forums/vstudio/en-US/820bf10f-3eaf-43a8-b5ef-b83b2394342c/windowsshowmodal-to-parentowner-window-only-not-entire-application?forum=wpf

También probé un enfoque de subprocesos de la interfaz de usuario múltiple, pero esto causó problemas con las bibliotecas de terceros (controles de caliburn micro y telerik wpf), ya que no están diseñados para ser utilizados en múltiples subprocesos de la interfaz de usuario. Es posible hacer que funcionen con varios subprocesos de interfaz de usuario, pero prefiero una solución más simple ...

Si implementa el cuadro de diálogo como se describe, ya no puede usar la propiedad DialogResult, ya que causaría que "DialogResult solo se pueda configurar después de crear y mostrar Windows como excepción". Solo implementa tu propia propiedad y úsala en su lugar.

Necesitas la siguiente referencia de API de 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);

Entonces usa esto:

// 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();

Este es el controlador de eventos que vuelve a habilitar la ventana principal, cuando se cierra el cuadro de diálogo:

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); } }

Y este es el ShowAndWaitHelper necesario para lograr el comportamiento del diálogo modal (esto bloquea la ejecución del hilo, pero sigue ejecutando el bucle de mensajes).

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; } }

Mi aplicación tiene varias ventanas de "nivel superior" independientes, todas con funciones / flujos de trabajo completamente diferentes.

Actualmente estoy usando ShowDialog () para hacer una ventana de WPF modal. La ventana modal es un hijo de una de las ventanas principales. Sin embargo, está bloqueando todas las ventanas de nivel superior una vez que está abierto. Me gustaría que el cuadro de diálogo bloquee SOLAMENTE la ventana principal desde la que se inició. es posible?

No estoy seguro de si importa, pero la ventana que abre el cuadro de diálogo es la ventana inicial de la aplicación, por lo que todas las demás ventanas de nivel superior se abren desde ella.


Una opción es iniciar las ventanas que no desea que se vean afectadas por el diálogo en un hilo diferente. Esto puede dar lugar a otros problemas para su aplicación, pero si esas ventanas realmente encapsulan flujos de trabajo diferentes, puede que no sea un problema. Aquí hay un código de ejemplo que escribí para verificar que esto funciona:

<Window x:Class="ModalSample.MyWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="{Binding Identifier}" Height="150" Width="150"> <StackPanel> <TextBox Text="{Binding Identifier}" /> <Button Content="Open Normal Child" Click="OpenNormal_Click" /> <Button Content="Open Independent Child" Click="OpenIndependent_Click" /> <Button Content="Open Modal Child" Click="OpenModal_Click" /> </StackPanel> </Window>

using System.ComponentModel; using System.Threading; using System.Windows; namespace ModalSample { /// <summary> /// Interaction logic for MyWindow.xaml /// </summary> public partial class MyWindow : INotifyPropertyChanged { public MyWindow() { InitializeComponent(); DataContext = this; } private int child = 1; private string mIdentifier = "Root"; public string Identifier { get { return mIdentifier; } set { if (mIdentifier == value) return; mIdentifier = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Identifier")); } } private void OpenNormal_Click(object sender, RoutedEventArgs e) { var window = new MyWindow {Identifier = Identifier + "-N" + child++}; window.Show(); } private void OpenIndependent_Click(object sender, RoutedEventArgs e) { var thread = new Thread(() => { var window = new MyWindow {Identifier = Identifier + "-I" + child++}; window.Show(); window.Closed += (sender2, e2) => window.Dispatcher.InvokeShutdown(); System.Windows.Threading.Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); } private void OpenModal_Click(object sender, RoutedEventArgs e) { var window = new MyWindow { Identifier = Identifier + "-M" + child++ }; window.ShowDialog(); } public event PropertyChangedEventHandler PropertyChanged; } }

Obtuve esta publicación del blog para ejecutar una ventana WPF en un hilo diferente.