web-dev-qa-db-fra.com

WPF: créer un dialogue / une invite

J'ai besoin de créer un dialogue/une invite comprenant une zone de texte pour la saisie de l'utilisateur. Mon problème est, comment obtenir le texte après avoir confirmé le dialogue? Habituellement, je ferais un cours pour cela qui sauverait le texte dans une propriété. Cependant, je souhaite concevoir le dialogue en utilisant XAML. Il me faudrait donc d'une certaine manière étendre le code XAML pour enregistrer le contenu de la zone de texte dans une propriété - mais je suppose que ce n'est pas possible avec du XAML pur. Quel serait le meilleur moyen de réaliser ce que j'aimerais faire? Comment construire un dialogue qui peut être défini à partir de XAML mais peut quand même renvoyer l’entrée? Merci pour tout indice!

71
stefan.at.wpf

La réponse "responsable" serait pour moi de suggérer de créer un ViewModel pour la boîte de dialogue et d'utiliser une liaison de données bidirectionnelle sur la zone de texte afin que ViewModel ait une propriété "ResponseText" ou non. C'est assez facile à faire, mais probablement excessif.

La réponse pragmatique serait simplement de donner à votre zone de texte un x: Name afin qu’elle devienne un membre et d’exposer le texte en tant que propriété dans votre code derrière la classe, comme ceci:

<!-- Incredibly simplified XAML -->
<Window x:Class="MyDialog">
   <StackPanel>
       <TextBlock Text="Enter some text" />
       <TextBox x:Name="ResponseTextBox" />
       <Button Content="OK" Click="OKButton_Click" />
   </StackPanel>
</Window>

Puis dans votre code derrière ...

partial class MyDialog : Window {

    public MyDialog() {
        InitializeComponent();
    }

    public string ResponseText {
        get { return ResponseTextBox.Text; }
        set { ResponseTextBox.Text = value; }
    }

    private void OKButton_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        DialogResult = true;
    }
}

Puis l'utiliser ...

var dialog = new MyDialog();
if (dialog.ShowDialog() == true) {
    MessageBox.Show("You said: " + dialog.ResponseText);
}
124
Josh

Je viens d'ajouter une méthode statique pour l'appeler comme un MessageBox:

<Window xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    x:Class="utils.PromptDialog"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    WindowStartupLocation="CenterScreen" 
    SizeToContent="WidthAndHeight"
    MinWidth="300"
    MinHeight="100"
    WindowStyle="SingleBorderWindow"
    ResizeMode="CanMinimize">
<StackPanel Margin="5">
    <TextBlock Name="txtQuestion" Margin="5"/>
    <TextBox Name="txtResponse" Margin="5"/>
    <PasswordBox Name="txtPasswordResponse" />
    <StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right">
        <Button Content="_Ok" IsDefault="True" Margin="5" Name="btnOk" Click="btnOk_Click" />
        <Button Content="_Cancel" IsCancel="True" Margin="5" Name="btnCancel" Click="btnCancel_Click" />
    </StackPanel>
</StackPanel>
</Window>

Et le code derrière:

public partial class PromptDialog : Window
{
    public enum InputType
    {
        Text,
        Password
    }

    private InputType _inputType = InputType.Text;

    public PromptDialog(string question, string title, string defaultValue = "", InputType inputType = InputType.Text)
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(PromptDialog_Loaded);
        txtQuestion.Text = question;
        Title = title;
        txtResponse.Text = defaultValue;
        _inputType = inputType;
        if (_inputType == InputType.Password)
            txtResponse.Visibility = Visibility.Collapsed;
        else
            txtPasswordResponse.Visibility = Visibility.Collapsed;
    }

    void PromptDialog_Loaded(object sender, RoutedEventArgs e)
    {
        if (_inputType == InputType.Password)
            txtPasswordResponse.Focus();
        else
            txtResponse.Focus();
    }

    public static string Prompt(string question, string title, string defaultValue = "", InputType inputType = InputType.Text)
    {
        PromptDialog inst = new PromptDialog(question, title, defaultValue, inputType);
        inst.ShowDialog();
        if (inst.DialogResult == true)
            return inst.ResponseText;
        return null;
    }

    public string ResponseText
    {
        get
        {
            if (_inputType == InputType.Password)
                return txtPasswordResponse.Password;
            else
                return txtResponse.Text;
        }
    }

    private void btnOk_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = true;
        Close();
    }

    private void btnCancel_Click(object sender, RoutedEventArgs e)
    {
        Close();
    }
}

Vous pouvez donc l'appeler comme suit:

string repeatPassword = PromptDialog.Prompt("Repeat password", "Password confirm", inputType: PromptDialog.InputType.Password);
30
Pythonizo

Excellente réponse de Josh, tout le mérite lui revient, je l'ai cependant légèrement modifié:

MyDialog Xaml

    <StackPanel Margin="5,5,5,5">
        <TextBlock Name="TitleTextBox" Margin="0,0,0,10" />
        <TextBox Name="InputTextBox" Padding="3,3,3,3" />
        <Grid Margin="0,10,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button Name="BtnOk" Content="OK" Grid.Column="0" Margin="0,0,5,0" Padding="8" Click="BtnOk_Click" />
            <Button Name="BtnCancel" Content="Cancel" Grid.Column="1" Margin="5,0,0,0" Padding="8" Click="BtnCancel_Click" />
        </Grid>
    </StackPanel>

Code MyDialog Derrière

    public MyDialog()
    {
        InitializeComponent();
    }

    public MyDialog(string title,string input)
    {
        InitializeComponent();
        TitleText = title;
        InputText = input;
    }

    public string TitleText
    {
        get { return TitleTextBox.Text; }
        set { TitleTextBox.Text = value; }
    }

    public string InputText
    {
        get { return InputTextBox.Text; }
        set { InputTextBox.Text = value; }
    }

    public bool Canceled { get; set; }

    private void BtnCancel_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        Canceled = true;
        Close();
    }

    private void BtnOk_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        Canceled = false;
        Close();
    }

Et appelez-le ailleurs

var dialog = new MyDialog("test", "hello");
dialog.Show();
dialog.Closing += (sender,e) =>
{
    var d = sender as MyDialog;
    if(!d.Canceled)
        MessageBox.Show(d.InputText);
}
15
xtds

Vous n'avez pas besoin [~ # ~] de [~ # ~] de ces réponses fantaisistes. Vous trouverez ci-dessous un exemple simpliste qui ne contient pas toutes les propriétés Margin, Height, Width définies dans le XAML, mais devrait suffire à montrer comment le faire à un niveau de base.

[~ # ~] xaml [~ # ~]
Construisez une page Window comme vous le feriez normalement et ajoutez-y vos champs, disons un contrôle Label et TextBox à l'intérieur d'un StackPanel:

<StackPanel Orientation="Horizontal">
    <Label Name="lblUser" Content="User Name:" />
    <TextBox Name="txtUser" />
</StackPanel>

Ensuite, créez un Button standard pour Soumission ("OK" ou "Soumettre") et un bouton "Annuler" si vous le souhaitez:

<StackPanel Orientation="Horizontal">
    <Button Name="btnSubmit" Click="btnSubmit_Click" Content="Submit" />
    <Button Name="btnCancel" Click="btnCancel_Click" Content="Cancel" />
</StackPanel>

Code-Behind
Vous allez ajouter les fonctions de gestionnaire d'événements Click dans le code-behind, mais lorsque vous y allez, déclarez d'abord une variable publique dans laquelle vous allez stocker la valeur de votre zone de texte:

public static string strUserName = String.Empty;

Ensuite, pour les fonctions du gestionnaire d’événements (cliquez avec le bouton droit de la souris sur la fonction Click du bouton XAML, sélectionnez "Aller à la définition", cela sera créé à votre place), vous devez vérifier si votre boîte est vide. . Vous le stockez dans votre variable si ce n'est pas le cas et fermez votre fenêtre:

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{        
    if (!String.IsNullOrEmpty(txtUser.Text))
    {
        strUserName = txtUser.Text;
        this.Close();
    }
    else
        MessageBox.Show("Must provide a user name in the textbox.");
}

Appeler depuis une autre page
Vous pensez que si je ferme la fenêtre avec cette this.Close() là-haut, ma valeur a disparu, n'est-ce pas? NON !! Je l'ai découvert sur un autre site: http://www.dreamincode.net/forums/topic/359208-wpf comment-faire-simple-popup-fenêtre-pour-input /

Ils avaient un exemple similaire à ceci (je l'ai un peu nettoyé) sur la façon d'ouvrir votre Window depuis un autre et de récupérer les valeurs:

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

    private void btnOpenPopup_Click(object sender, RoutedEventArgs e)
    {
        MyPopupWindow popup = new MyPopupWindow();  // this is the class of your other page

        //ShowDialog means you can't focus the parent window, only the popup
        popup.ShowDialog(); //execution will block here in this method until the popup closes

        string result = popup.strUserName;
        UserNameTextBlock.Text = result;  // should show what was input on the other page
    }
}

Bouton Annuler
Vous pensez, eh bien, qu'en est-il de ce bouton Annuler? Nous ajoutons donc simplement une autre variable publique dans notre fenêtre contextuelle code-behind:

public static bool cancelled = false;

Et ajoutons notre gestionnaire d'événement btnCancel_Click Et apportons une modification à btnSubmit_Click:

private void btnCancel_Click(object sender, RoutedEventArgs e)
{        
    cancelled = true;
    strUserName = String.Empty;
    this.Close();
}

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{        
    if (!String.IsNullOrEmpty(txtUser.Text))
    {
        strUserName = txtUser.Text;
        cancelled = false;  // <-- I add this in here, just in case
        this.Close();
    }
    else
        MessageBox.Show("Must provide a user name in the textbox.");
}

Et puis nous venons de lire cette variable dans notre événement MainWindowbtnOpenPopup_Click:

private void btnOpenPopup_Click(object sender, RoutedEventArgs e)
{
    MyPopupWindow popup = new MyPopupWindow();  // this is the class of your other page
    //ShowDialog means you can't focus the parent window, only the popup
    popup.ShowDialog(); //execution will block here in this method until the popup closes

    // **Here we find out if we cancelled or not**
    if (popup.cancelled == true)
        return;
    else
    {
        string result = popup.strUserName;
        UserNameTextBlock.Text = result;  // should show what was input on the other page
    }
}

Longue réponse, mais je voulais montrer à quel point il est facile d'utiliser des variables public static. Non DialogResult, aucune valeur renvoyée, rien. Ouvrez simplement la fenêtre, stockez vos valeurs avec les événements de bouton dans la fenêtre contextuelle, puis récupérez-les ensuite dans la fonction de fenêtre principale.

2
vapcguy