Jak zrobić modalne okno dialogowe w WPF?

140

Piszę moją pierwszą aplikację w WPF i chcę, aby użytkownik wprowadził pewne dane w modalnym oknie dialogowym. Najwyraźniej nie jest to łatwe do wykonania w WPF, ponieważ okno nadrzędne pozostaje w pełni włączone, a metoda, która utworzyła nowe okno podrzędne, nie zatrzymuje się i nie czeka na wywołanie funkcji Close () przez okno podrzędne. Zamiast tego po prostu idzie do przodu. Nie tego chcę.

Jak sprawić, aby okno podrzędne było otwierane i aby okno nadrzędne oczekiwało na zamknięcie okna podrzędnego, zanim okno nadrzędne będzie kontynuowane?

Alex Baranosky
źródło
Udostępniam tutaj moją odpowiedź , ponieważ może to pomóc komuś tułającemu się z Google.
Shahin Dohan

Odpowiedzi:

227

Czy próbowałeś pokazać swoje okno za pomocą metody ShowDialog ?

Nie zapomnij ustawić właściwości Owner w oknie dialogowym na okno główne. Pozwoli to uniknąć dziwnego zachowania, gdy Alt + Tab, itp.

Yordan Pavlov
źródło
50

Wiele z tych odpowiedzi jest uproszczonych, a jeśli ktoś zaczyna WPF, może nie znać wszystkich „wejść i wyjść”, ponieważ jest to bardziej skomplikowane niż zwykłe powiedzenie komuś „Użyj .ShowDialog()!”. Ale to jest metoda (nie .Show()), której chcesz użyć, aby zablokować użycie okna bazowego i aby kod nie był kontynuowany, dopóki okno modalne nie zostanie zamknięte.

Najpierw potrzebujesz 2 okien WPF. (Jeden będzie dzwonił do drugiego.)

Załóżmy, że z pierwszego okna, które nazywało się MainWindow.xaml, w jego kodzie za nim będzie:

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

Następnie dodaj przycisk do kodu XAML:

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

Kliknij Clickprocedurę prawym przyciskiem myszy i wybierz opcję „Przejdź do definicji”. Stworzy go dla Ciebie w MainWindow.xaml.cs:

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

W ramach tej funkcji musisz określić drugą stronę za pomocą jej klasy strony. Powiedzmy, że nazwałeś tę drugą stronę „ModalWindow”, tak aby stała się ona klasą strony i tak można ją utworzyć (wywołać):

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

Załóżmy, że masz wartość, którą chcesz ustawić w oknie modalnym. Utwórz pole tekstowe i przycisk w ModalWindowXAML:

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

Następnie ponownie utwórz procedurę obsługi zdarzenia (inne Clickzdarzenie) i użyj jej do zapisania wartości pola tekstowego w publicznej zmiennej statycznej ModalWindowi wywołaj 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();
    }
}

Następnie po złożeniu .ShowDialog()oświadczenia możesz pobrać tę wartość i użyć jej:

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

    string valueFromModalTextBox = ModalWindow.myValue;
}
vapcguy
źródło
30

Window.Show Window pokaże okno i będzie kontynuować wykonywanie - jest to wywołanie nieblokujące.

Window.ShowDialog zablokuje wątek wywołujący (w pewnym sensie [1]) i wyświetli okno dialogowe. Blokuje również interakcję z oknem nadrzędnym / właścicielem. Gdy okno dialogowe zostanie zamknięte (z dowolnego powodu) ShowDialog powróci do dzwoniącego i umożliwi dostęp do DialogResult (jeśli chcesz).

[1] Będzie utrzymywać pompowanie przez dyspozytora poprzez wpychanie ramki dyspozytora na dipatcher WPF. Spowoduje to, że komunikat pompa będzie dalej pompować.

Dominic Hopton
źródło
wyjaśnij to bardziej szczegółowo, proszę? Patrzę na podobny problem, w którym mam uruchomiony proces testowy, ale komunikaty ostrzegawcze mogą pojawiać się jako modalne okna dialogowe, ale nie chcę blokować wykonywania.
Firoso
2

Mając obiekt Window myWindow, myWindow.Show () otworzy go w sposób modelowy, a myWindow.ShowDialog () otworzy go modalnie. Jednak nawet ta ostatnia nie blokuje, z tego co pamiętam.

szkody
źródło
6
Myślę, że to blokuje. Kod po myWindow.Show () nie jest wykonywany, dopóki myWindow nie wywoła Close ().
Alex Baranosky
Zarówno ty, jak i @AlexBaranosky jesteście poprawni: ShowDialognie wraca, dopóki modal nie zostanie zamknięty, więc blokuje aktualnie wykonywaną operację wysyłającą. Ale ShowDialogsam skutecznie wywołuje Dispatcher.Run(), więc dyspozytor kontynuuje wykonywanie operacji, w efekcie utrzymując responsywność interfejsu użytkownika.
Matt Thomas,