Как сделать модальный диалог в WPF?

133

Я пишу свое первое приложение в WPF и хочу, чтобы пользователь вводил некоторые данные в модальном диалоговом окне. По-видимому, сделать это в WPF непросто, потому что родительское окно остается полностью включенным, а метод, создавший новое дочернее окно, не останавливается и не ждет, пока дочернее окно вызовет Close (). Вместо этого он просто продолжает идти вперед. Это не то, что я хочу.

Как я могу открыть дочернее окно и заставить родительское окно ждать закрытия дочернего окна, прежде чем родительское окно продолжит выполнение?

Алекс Бараноский
источник
Поделюсь своим ответом здесь, так как это может помочь кому-то из Google.
Шахин

Ответы:

222

Вы пытались показать свое окно с помощью метода ShowDialog ?

Не забудьте установить свойство Owner в диалоговом окне на главное окно. Это позволит избежать странного поведения при нажатии Alt + Tab и т. Д.

Йордан Павлов
источник
43

Многие из этих ответов упрощены, и если кто-то начинает WPF, он может не знать всех «входов и выходов», поскольку это сложнее, чем просто сказать кому-то «Используйте .ShowDialog()!». Но это метод (а не .Show()), который вы хотите использовать, чтобы заблокировать использование нижележащего окна и предотвратить продолжение выполнения кода до закрытия модального окна.

Во-первых, вам нужно 2 окна WPF. (Один будет звонить другому.)

Предположим, из первого окна оно называлось MainWindow.xaml, в его коде программной части будет:

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

Затем добавьте свою кнопку в свой XAML:

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

И щелкните Clickпроцедуру правой кнопкой мыши , выберите «Перейти к определению». Он создаст его для вас в MainWindow.xaml.cs:

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

Внутри этой функции вы должны указать другую страницу, используя ее класс страницы. Допустим, вы назвали эту другую страницу «ModalWindow», так что она становится ее классом страницы, и именно так вы можете создать (вызвать) его:

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

Скажем, у вас есть значение, которое вам нужно установить в модальном диалоговом окне. Создайте текстовое поле и кнопку в ModalWindowXAML:

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

Затем Clickснова создайте обработчик события (другое событие) и используйте его, чтобы сохранить значение текстового поля в общедоступной статической переменной ModalWindowи вызвать 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();
    }
}

Затем, после вашего .ShowDialog()утверждения, вы можете взять это значение и использовать его:

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

    string valueFromModalTextBox = ModalWindow.myValue;
}
vapcguy
источник
29

Window.Show Window покажет окно и продолжит выполнение - это неблокирующий вызов.

Window.ShowDialog заблокирует вызывающий поток (kinda [1]) и покажет диалог. Он также заблокирует взаимодействие с родительским окном / окном-владельцем. Когда диалоговое окно закрыто (по какой-либо причине) ShowDialog вернется к вызывающему и позволит вам получить доступ к DialogResult (если вы этого хотите).

[1] Он будет поддерживать перекачку диспетчера, помещая кадр диспетчера в дипатчер WPF. Это заставит насос сообщений продолжать перекачивание.

Доминик Хоптон
источник
объясните это поподробнее пожалуйста? Я смотрю на аналогичную проблему, когда у меня запущен тестовый процесс, но предупреждающие сообщения могут появляться в виде модальных диалогов, но я не хочу блокировать выполнение.
Firoso,
2

При наличии объекта Window myWindow myWindow.Show () откроет его немодально, а myWindow.ShowDialog () откроет его модально. Однако даже последний не блокирует, насколько я помню.

Хармс
источник
6
Я считаю, что это блокирует. Код после myWindow.Show () не выполняется до тех пор, пока myWindow не вызовет Close ().
Alex Baranosky
И вы, и @AlexBaranosky правы: ShowDialogне возвращается, пока модальное окно не будет закрыто, поэтому оно блокирует выполняемую в данный момент операцию диспетчера. Но ShowDialogсам фактически вызывает Dispatcher.Run(), поэтому диспетчер продолжает выполнять операции, по сути, сохраняя отклик пользовательского интерфейса.
Мэтт Томас