Comment créer une boîte de dialogue modale dans WPF?

133

J'écris ma première application dans WPF et je souhaite que l'utilisateur saisisse des données dans une fenêtre de dialogue modale. Apparemment, ce n'est pas simple à faire dans WPF, car la fenêtre parente reste entièrement activée et la méthode qui a créé la nouvelle fenêtre enfant ne s'arrête pas et n'attend pas que la fenêtre enfant appelle Close (). Au lieu de cela, il continue d'avancer. Ce n'est pas ce que je veux.

Comment puis-je ouvrir la fenêtre enfant et demander à la fenêtre parent d'attendre la fermeture de l'enfant avant que la fenêtre parent ne continue de s'exécuter?

Alex Baranosky
la source
Partager ma réponse ici, car cela pourrait aider quelqu'un à errer ici depuis Google.
Shahin Dohan

Réponses:

222

Avez-vous essayé d'afficher votre fenêtre en utilisant la méthode ShowDialog ?

N'oubliez pas de définir la propriété Owner dans la fenêtre de dialogue sur la fenêtre principale. Cela évitera un comportement étrange lorsque Alt + Tabbing, etc.

Yordan Pavlov
la source
43

Beaucoup de ces réponses sont simplistes, et si quelqu'un commence WPF, il se peut qu'il ne connaisse pas tous les «tenants et aboutissants», car c'est plus compliqué que de simplement dire à quelqu'un «Utilisez .ShowDialog()!». Mais c'est la méthode (non .Show()) que vous souhaitez utiliser pour bloquer l'utilisation de la fenêtre sous-jacente et empêcher le code de continuer jusqu'à ce que la fenêtre modale soit fermée.

Tout d'abord, vous avez besoin de 2 fenêtres WPF. (L'un appellera l'autre.)

À partir de la première fenêtre, disons que cela s'appelait MainWindow.xaml, dans son code-behind sera:

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

Ajoutez ensuite votre bouton à votre XAML:

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

Et cliquez avec le bouton droit sur la Clickroutine, sélectionnez "Aller à la définition". Il le créera pour vous dans MainWindow.xaml.cs:

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

Dans cette fonction, vous devez spécifier l'autre page en utilisant sa classe de page. Supposons que vous ayez nommé cette autre page "ModalWindow", pour qu'elle devienne sa classe de page et que vous souhaitiez l'instancier (l'appeler):

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

Supposons que vous ayez une valeur à définir dans votre boîte de dialogue modale. Créez une zone de texte et un bouton dans le ModalWindowXAML:

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

Ensuite, créez à nouveau un gestionnaire d'événements (un autre Clickévénement) et utilisez-le pour enregistrer la valeur de la zone de texte dans une variable statique publique sur ModalWindowet appelez 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();
    }
}

Ensuite, après votre .ShowDialog()déclaration, vous pouvez saisir cette valeur et l'utiliser:

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

    string valueFromModalTextBox = ModalWindow.myValue;
}
vapcguy
la source
29

Window.Show Window affichera la fenêtre et poursuivra l'exécution - c'est un appel non bloquant.

Window.ShowDialog bloquera le thread appelant (un peu [1]) et affichera la boîte de dialogue. Cela bloquera également l'interaction avec la fenêtre parent / propriétaire. Lorsque la boîte de dialogue est fermée (pour quelque raison que ce soit) ShowDialog retournera à l'appelant et vous permettra d'accéder à DialogResult (si vous le souhaitez).

[1] Il maintiendra le pompage du répartiteur en poussant un cadre de répartiteur sur le dipatcher WPF. Cela entraînera la pompe à message de continuer à pomper.

Dominic Hopton
la source
expliquer cela plus en détail s'il vous plaît? Je regarde un problème similaire où j'ai un processus de test en cours d'exécution, mais des messages d'avertissement peuvent apparaître sous forme de boîtes de dialogue modales mais je ne veux pas bloquer l'exécution.
Firoso
2

Étant donné un objet Window myWindow, myWindow.Show () l'ouvrira de manière modale et myWindow.ShowDialog () l'ouvrira de manière modale. Cependant, même ce dernier ne bloque pas, d'après ce dont je me souviens.

nuit
la source
6
Je crois que ça bloque. Le code après que myWindow.Show () ne s'exécute qu'après que myWindow appelle Close ().
Alex Baranosky le
Vous et @AlexBaranosky avez raison: ShowDialogne retourne pas tant que le modal n'est pas fermé, il bloque donc l'opération de répartiteur en cours d'exécution. Mais ShowDialoglui-même appelle efficacement Dispatcher.Run(), de sorte que le répartiteur continue d'exécuter les opérations, en maintenant l'interface utilisateur réactive.
Matt Thomas