Wie erstelle ich einen modalen Dialog in WPF?


133

Ich schreibe meine erste Anwendung in WPF und möchte, dass der Benutzer einige Daten in ein modales Dialogfenster eingibt. Anscheinend ist dies in WPF nicht einfach, da das übergeordnete Fenster vollständig aktiviert bleibt und die Methode, mit der das neue untergeordnete Fenster erstellt wurde, nicht stoppt und darauf wartet, dass das untergeordnete Fenster Close () aufruft. Stattdessen geht es einfach weiter. Das will ich nicht.

Wie kann ich das untergeordnete Fenster öffnen und das übergeordnete Fenster warten lassen, bis das untergeordnete Fenster geschlossen ist, bevor das übergeordnete Fenster weiter ausgeführt wird?


Teilen Sie meine Antwort hier, da dies möglicherweise dazu beiträgt, dass jemand von Google hierher wandert.
Shahin Dohan

Antworten:



43

Viele dieser Antworten sind simpel, und wenn jemand mit der WPF beginnt, kennt er möglicherweise nicht alle "Vor- und Nachteile", da dies komplizierter ist, als nur jemandem "Verwenden .ShowDialog()!" Zu sagen . Dies ist jedoch die Methode (nicht .Show()), die Sie verwenden möchten, um die Verwendung des zugrunde liegenden Fensters zu blockieren und zu verhindern, dass der Code fortgesetzt wird, bis das modale Fenster geschlossen wird.

Zunächst benötigen Sie 2 WPF-Fenster. (Einer wird den anderen anrufen.)

Nehmen wir vom ersten Fenster an an, dass MainWindow.xaml in seinem Code-Behind heißt:

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

Fügen Sie dann Ihre Schaltfläche zu Ihrer XAML hinzu:

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

Klicken Sie mit der rechten Maustaste auf die ClickRoutine und wählen Sie "Zur Definition gehen". Es wird es für Sie in MainWindow.xaml.cs erstellen:

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

Innerhalb dieser Funktion müssen Sie die andere Seite anhand ihrer Seitenklasse angeben. Angenommen, Sie haben diese andere Seite "ModalWindow" genannt, damit sie zu ihrer Seitenklasse wird und Sie sie instanziieren (aufrufen) würden:

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

Angenommen, Sie haben einen Wert festgelegt, den Sie in Ihrem modalen Dialogfeld festlegen müssen. Erstellen Sie ein Textfeld und eine Schaltfläche in der ModalWindowXAML:

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

Erstellen Sie dann erneut einen Ereignishandler (ein anderes ClickEreignis) und verwenden Sie ihn, um den Textfeldwert in einer öffentlichen statischen Variablen zu speichern ModalWindowund aufzurufen 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();
    }
}

Nach Ihrer .ShowDialog()Aussage können Sie diesen Wert abrufen und verwenden:

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

    string valueFromModalTextBox = ModalWindow.myValue;
}

29

Window.Show Window zeigt das Fenster an und setzt die Ausführung fort - es ist ein nicht blockierender Aufruf.

Window.ShowDialog blockiert den aufrufenden Thread (irgendwie [1]) und zeigt den Dialog an. Außerdem wird die Interaktion mit dem übergeordneten / besitzenden Fenster blockiert. Wenn der Dialog geschlossen wird (aus welchem ​​Grund auch immer), kehrt ShowDialog zum Aufrufer zurück und ermöglicht Ihnen den Zugriff auf DialogResult (falls gewünscht).

[1] Der Dispatcher wird weiter gepumpt, indem ein Dispatcher-Rahmen auf den WPF-Dipatcher gedrückt wird. Dadurch pumpt die Meldungspumpe weiter.


Erklären Sie dies bitte genauer. Ich sehe ein ähnliches Problem, bei dem ein Testprozess ausgeführt wird, aber Warnmeldungen als modale Dialoge angezeigt werden können, aber ich möchte die Ausführung nicht blockieren.
Firoso

2

Wenn ein Window-Objekt myWindow gegeben ist, öffnet myWindow.Show () es modelllos und myWindow.ShowDialog () öffnet es modal. Aber auch letzteres blockiert nicht, soweit ich mich erinnere.


6
Ich glaube, es blockiert. Code nach myWindow.Show () wird erst ausgeführt, nachdem myWindow Close () aufgerufen hat.
Alex Baranosky

Sowohl Sie als auch @AlexBaranosky sind korrekt: Sie ShowDialogkehren erst zurück, wenn das Modal geschlossen ist, und blockieren daher den aktuell ausgeführten Dispatcher-Vorgang. Aber ShowDialogselbst ruft effektiv auf Dispatcher.Run(), so dass der Dispatcher weiterhin Operationen ausführt, wodurch die Benutzeroberfläche reaktionsfähig bleibt.
Matt Thomas
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.