Como criar diálogo modal no WPF?

133

Estou escrevendo meu primeiro aplicativo no WPF e quero que o usuário insira alguns dados em uma janela de diálogo modal. Aparentemente, isso não é fácil de fazer no WPF, porque a janela pai permanece totalmente ativada e o método que criou a nova janela filho não para e aguarda a janela filho chamar Close (). Em vez disso, continua seguindo em frente. Não é isso que eu quero.

Como posso abrir a janela filho e esperar que o filho feche antes que a janela pai continue em execução?

Alex Baranosky
fonte
Compartilhando minha resposta aqui, pois isso pode ajudar alguém que está aqui do Google.
Shahin Dohan

Respostas:

222

Você tentou mostrar sua janela usando o ShowDialog método ?

Não se esqueça de definir a propriedade Proprietário na janela de diálogo para a janela principal. Isso evitará comportamentos estranhos ao pressionar Alt + Tab, etc.

Yordan Pavlov
fonte
43

Muitas dessas respostas são simplistas e, se alguém está iniciando o WPF, pode não conhecer todas as "entradas e saídas", pois é mais complicado do que dizer a alguém "Use .ShowDialog()!". Mas esse é o método (não.Show() ) que você deseja usar para bloquear o uso da janela subjacente e impedir que o código continue até que a janela modal seja fechada.

Primeiro, você precisa de 2 janelas WPF. (Um vai ligar para o outro.)

Na primeira janela, digamos que se chame MainWindow.xaml, em seu code-behind será:

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

Em seguida, adicione seu botão ao seu XAML:

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

E clique com o botão direito do mouse na Clickrotina, selecione "Ir para a definição". Ele será criado para você no MainWindow.xaml.cs:

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

Dentro dessa função, você deve especificar a outra página usando sua classe de página. Digamos que você nomeou essa outra página como "ModalWindow", para que ela se torne sua classe de página e é como você a instanciaria (chamava):

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

Digamos que você tenha um valor que precisa definir na sua caixa de diálogo modal. Crie uma caixa de texto e um botão no ModalWindowXAML:

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

Em seguida, crie um manipulador de eventos (outro Clickevento) novamente e use-o para salvar o valor da caixa de texto em uma variável estática pública ModalWindowe ligar 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();
    }
}

Depois da sua .ShowDialog()declaração, você pode pegar esse valor e usá-lo:

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

    string valueFromModalTextBox = ModalWindow.myValue;
}
vapcguy
fonte
29

Window.Show Window mostrará a janela e continuará a execução - é uma chamada sem bloqueio.

Window.ShowDialog irá bloquear o segmento de chamada (meio que [1]) e mostrar a caixa de diálogo. Ele também bloqueará a interação com a janela principal / proprietária. Quando a caixa de diálogo é descartada (por qualquer motivo), o ShowDialog retornará ao chamador e permitirá que você acesse o DialogResult (se desejar).

[1] Ele manterá o expedidor bombeando, empurrando uma estrutura do expedidor para o Dipatcher WPF. Isso fará com que a bomba de mensagens continue bombeando.

Dominic Hopton
fonte
explique isso com mais detalhes, por favor? Estou procurando um problema semelhante em que tenho um processo de teste em execução, mas as mensagens de aviso podem aparecer como caixas de diálogo modais, mas não quero bloquear a execução.
Firoso 30/10/09
2

Dado um objeto Window, myWindow, myWindow.Show () o abrirá de maneira independente e myWindow.ShowDialog () o abrirá de maneira modal. No entanto, mesmo este último não bloqueia, pelo que me lembro.

prejudica
fonte
6
Eu acredito que bloqueia. O código após o myWindow.Show () não estar em execução até que o myWindow chame Close ().
Alex Baranosky
Você e o @AlexBaranosky estão corretos: ShowDialognão retornam até o modal ser fechado e, portanto, bloqueiam a operação do despachante em execução no momento. Mas ShowDialogele efetivamente chama Dispatcher.Run(), de modo que o expedidor continua executando as operações, mantendo a interface do usuário responsiva.
Thomas