¿Cómo hacer un diálogo modal en WPF?

133

Estoy escribiendo mi primera aplicación en WPF y quiero que el usuario ingrese algunos datos en una ventana de diálogo modal. Aparentemente, esto no es fácil de hacer en WPF, porque la ventana principal permanece totalmente habilitada, y el método que creó la nueva ventana secundaria no se detiene y espera a que la ventana secundaria llame a Close (). En cambio, sigue avanzando. Esto no es lo que quiero.

¿Cómo puedo hacer que se abra la ventana secundaria y hacer que la ventana principal espere a que se cierre antes de que la ventana principal continúe ejecutándose?

Alex Baranosky
fuente
Comparto mi respuesta aquí, ya que podría ayudar a alguien que vaga por Google.
Shahin Dohan

Respuestas:

222

¿Intentaste mostrar tu ventana usando el método ShowDialog ?

No olvide establecer la propiedad Propietario en la ventana de diálogo en la ventana principal. Esto evitará un comportamiento extraño cuando Alt + Tabbing, etc.

Yordan Pavlov
fuente
43

Muchas de estas respuestas son simplistas, y si alguien está comenzando WPF, es posible que no conozca todos los "entresijos", ya que es más complicado que decirle a alguien " .ShowDialog()¡ Usa !". Pero ese es el método (no .Show()) que desea utilizar para bloquear el uso de la ventana subyacente y evitar que el código continúe hasta que se cierre la ventana modal.

Primero, necesitas 2 ventanas WPF. (Uno llamará al otro).

Desde la primera ventana, digamos que se llamó MainWindow.xaml, en su código subyacente será:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

Luego agrega tu botón a tu XAML:

<Button Name="btnOpenModal" Click="btnOpenModal_Click" Content="Open Modal" />

Y haga clic derecho en la Clickrutina, seleccione "Ir a definición". Lo creará para usted en MainWindow.xaml.cs:

private void btnOpenModal_Click(object sender, RoutedEventArgs e)
{
}

Dentro de esa función, debe especificar la otra página utilizando su clase de página. Supongamos que nombró a esa otra página "ModalWindow", de modo que se convierte en su clase de página y así es como la instanciaría (llamaría):

private void btnOpenModal_Click(object sender, RoutedEventArgs e)
{
    ModalWindow modalWindow = new ModalWindow();
    modalWindow.ShowDialog();
}

Digamos que tiene un valor que necesita establecer en su diálogo modal. Cree un cuadro de texto y un botón en ModalWindowXAML:

<StackPanel Orientation="Horizontal">
    <TextBox Name="txtSomeBox" />
    <Button Name="btnSaveData" Click="btnSaveData_Click" Content="Save" /> 
</StackPanel>

Luego, Clickvuelva a crear un controlador de eventos (otro evento) y úselo para guardar el valor del cuadro de texto en una variable estática pública ModalWindowy llame this.Close().

public partial class ModalWindow : Window
{
    public static string myValue = String.Empty;        
    public ModalWindow()
    {
        InitializeComponent();
    }

    private void btnSaveData_Click(object sender, RoutedEventArgs e)
    {
        myValue = txtSomeBox.Text;
        this.Close();
    }
}

Luego, después de su .ShowDialog()declaración, puede tomar ese valor y usarlo:

private void btnOpenModal_Click(object sender, RoutedEventArgs e)
{
    ModalWindow modalWindow = new ModalWindow();
    modalWindow.ShowDialog();

    string valueFromModalTextBox = ModalWindow.myValue;
}
vapcguy
fuente
29

Window.Show Window mostrará la ventana y continuará la ejecución: es una llamada sin bloqueo.

Window.ShowDialog bloqueará el hilo de llamada (un poco [1]) y mostrará el diálogo. También bloqueará la interacción con la ventana principal / propietaria. Cuando se cierra el cuadro de diálogo (por cualquier razón) ShowDialog volverá a la persona que llama y le permitirá acceder a DialogResult (si lo desea).

[1] Mantendrá al despachador bombeando empujando un marco de despachador en el dipatcher WPF. Esto hará que la bomba de mensaje siga bombeando.

Dominic Hopton
fuente
explicar esto con más detalle por favor? Estoy viendo un problema similar en el que tengo un proceso de prueba ejecutándose pero los mensajes de advertencia pueden aparecer como cuadros de diálogo modales, pero no quiero bloquear la ejecución.
Firoso
2

Dado un objeto de ventana myWindow, myWindow.Show () lo abrirá sin modo y myWindow.ShowDialog () lo abrirá modalmente. Sin embargo, incluso este último no bloquea, por lo que recuerdo.

daños
fuente
66
Creo que bloquea. El código después de myWindow.Show () no se ejecuta hasta que myWindow llama a Close ().
Alex Baranosky
Tanto usted como @AlexBaranosky son correctos: ShowDialogno regresa hasta que se cierra el modal, por lo que bloquea la operación del despachador que se está ejecutando actualmente. Pero ShowDialogsí efectivamente llama Dispatcher.Run(), por lo que el despachador continúa ejecutando operaciones, en efecto manteniendo la interfaz de usuario receptiva.
Matt Thomas