Bagaimana cara membuat dialog modal dalam WPF?

133

Saya menulis aplikasi pertama saya di WPF dan ingin agar pengguna memasukkan beberapa data pada jendela dialog modal. Tampaknya, ini tidak mudah dilakukan di WPF, karena jendela induk tetap diaktifkan sepenuhnya, dan metode yang membuat jendela anak baru tidak berhenti dan menunggu jendela anak untuk memanggil Tutup (). Sebaliknya itu hanya terus maju. Ini bukan yang saya inginkan.

Bagaimana saya bisa membuka jendela anak, dan membiarkan jendela induk menunggu anak menutup sebelum jendela induk terus dijalankan?

Alex Baranosky
sumber
Membagikan jawaban saya di sini karena mungkin membantu seseorang berkeliaran di sini dari Google.
Shahin Dohan

Jawaban:

222

Apakah Anda mencoba menampilkan jendela menggunakan metode ShowDialog ?

Jangan lupa untuk mengatur properti Owner di jendela dialog ke jendela utama. Ini akan menghindari perilaku aneh ketika Alt + Tab, dll.

Yordan Pavlov
sumber
43

Banyak jawaban ini sederhana, dan jika seseorang memulai WPF, mereka mungkin tidak mengetahui semua "seluk beluk", karena lebih rumit daripada hanya mengatakan pada seseorang "Gunakan .ShowDialog()!". Tetapi itu adalah metode (bukan .Show()) yang ingin Anda gunakan untuk memblokir penggunaan jendela yang mendasarinya dan untuk menjaga kode dari melanjutkan sampai jendela modal ditutup.

Pertama, Anda membutuhkan 2 jendela WPF. (Satu akan memanggil yang lain.)

Dari jendela pertama, katakanlah yang disebut MainWindow.xaml, di belakangnya adalah:

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

Kemudian tambahkan tombol Anda ke XAML Anda:

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

Dan klik kanan Clickrutinnya, pilih "Pergi ke definisi". Ini akan membuatnya untuk Anda di MainWindow.xaml.cs:

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

Dalam fungsi itu, Anda harus menentukan halaman lain menggunakan kelas halamannya. Katakanlah Anda memberi nama halaman lain itu "ModalWindow", sehingga itu menjadi kelas halamannya dan bagaimana Anda akan instantiate (panggil) itu:

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

Katakanlah Anda memiliki nilai yang perlu Anda tetapkan pada dialog modal Anda. Buat kotak teks dan tombol di ModalWindowXAML:

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

Kemudian buat pengendali acara ( Clickevent lain ) lagi dan gunakan untuk menyimpan nilai textbox ke variabel statis publik ModalWindowdan panggil 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();
    }
}

Kemudian, setelah .ShowDialog()pernyataan Anda, Anda bisa mengambil nilai itu dan menggunakannya:

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

    string valueFromModalTextBox = ModalWindow.myValue;
}
vapcguy
sumber
29

Window.Show Window akan menampilkan jendela, dan melanjutkan eksekusi - ini adalah panggilan yang tidak menghalangi.

Window.ShowDialog akan memblokir utas panggilan (agak [1]), dan menampilkan dialog. Ini juga akan memblokir interaksi dengan jendela induk / pemilik. Ketika dialog ditolak (untuk alasan apa pun) ShowDialog akan kembali ke pemanggil, dan akan memungkinkan Anda untuk mengakses DialogResult (jika Anda menginginkannya).

[1] Ini akan membuat pompa dispatcher dengan mendorong bingkai dispatcher ke dipatcher WPF. Ini akan menyebabkan pompa pesan terus memompa.

Dominic Hopton
sumber
tolong jelaskan hal ini lebih detail? Saya melihat masalah yang sama di mana saya memiliki proses pengujian berjalan tetapi pesan peringatan dapat muncul sebagai dialog modal tetapi saya tidak ingin memblokir eksekusi.
Firoso
2

Diberikan objek Window myWindow, myWindow.Show () akan membukanya secara modeless dan myWindow.ShowDialog () akan membukanya secara modally. Namun, bahkan yang terakhir tidak menghalangi, dari apa yang saya ingat.

merugikan
sumber
6
Saya percaya itu menghalangi. Kode setelah myWindow.Show () tidak dijalankan sampai setelah myWindow memanggil Tutup ().
Alex Baranosky
Baik Anda dan @AlexBaranosky benar: ShowDialogtidak kembali sampai modal ditutup, sehingga memblokir operasi operator yang saat ini menjalankan. Tapi ShowDialogitu sendiri secara efektif memanggil Dispatcher.Run(), sehingga operator terus menjalankan operasi, yang pada dasarnya menjaga UI responsif.
Matt Thomas