2010-05-09 12 views
61

Ich muss eine Dialog/Eingabeaufforderung einschließlich TextBox für Benutzereingaben erstellen. Mein Problem ist, wie bekomme ich den Text, nachdem ich den Dialog bestätigt habe? Normalerweise würde ich eine Klasse dafür machen, die den Text in einer Eigenschaft speichern würde. Allerdings möchte ich den Dialog mit XAML gestalten. Also müsste ich irgendwie den XAML-Code erweitern, um den Inhalt der TextBox in einer Eigenschaft zu speichern - aber das ist bei reinem XAML nicht möglich. Was wäre der beste Weg, um zu realisieren, was ich tun möchte? Wie man einen Dialog baut, der von XAML definiert werden kann, aber irgendwie die Eingabe irgendwie zurückgeben kann? Danke für einen Hinweis!WPF: Erstellen eines Dialogfelds/Eingabeaufforderung

Antwort

109

Die "verantwortliche" Antwort wäre für mich zu empfehlen, ein ViewModel für den Dialog zu erstellen und eine zweiseitige Datenbindung für die TextBox zu verwenden, damit das ViewModel eine "ResponseText" -Eigenschaft hat oder was nicht. Das ist leicht genug zu tun, aber wahrscheinlich zu viel.

wäre die pragmatische Antwort nur Ihr Textfeld eine x geben: Namen, so dass es ein Mitglied wird und den Text als eine Eigenschaft in Ihrem Code Behind-Klasse wie so aussetzen:

<!-- 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> 

Dann in Ihrem Code hinter ...

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; 
    } 
} 

Dann, es zu benutzen ...

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

Vielen Dank Josh und Entschuldigung für meine späte Antwort! Ich war anfangs zu sehr darauf konzentriert, XAML aus einer Datei zu laden, anstatt nur eine Klasse wie von Ihnen gezeigt zu erstellen. –

+2

+1 für den Hinweis auf einen pragmatischen Ansatz :) – Jedidja

+6

Sie müssen mit dem Klick-Ereignis der OK-Schaltfläche umgehen und dies festlegen.DialogResult = true; um den Dialog zu schließen und dialog.ShowDialog() == true zu haben. –

15

Große Antwort von Josh, alle

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> 

MyDialog Code hinter

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(); 
    } 

Und es irgendwo anders nennen

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

Sie sollten (in Ihrer Rasterdefinition xaml) 50 * und 50 * durch * und * ersetzen, da keine Notwendigkeit für 50 besteht. – Mafii

24

ich nur noch hinzufügen: Kredit zu ihm, ich kann es leicht zu diesem jedoch geändert eine statische Methode, um es wie eine MessageBox aufzurufen:

<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> 

Und der Code hinter:

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(); 
    } 
} 

So kann man es nennen mag:

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

+1 Für die Implementierung einer 'MessageBox'-style Methode. Kurzer, wiederverwendbarer Code! –

+1

Sobald ich das Wort "statisch" sah, ignorierte ich die anderen Antworten. Vielen Dank! :) – maplemale

2

Sie brauchen nicht ANY diese anderen ausgefallenen Antworten. Unten ist ein einfaches Beispiel, das nicht alle Margin, Height, Width Eigenschaften in XAML festgelegt hat, aber sollte genug sein, um zu zeigen, wie dies auf einer grundlegenden Ebene getan wird.

XAML
Erstellen Sie eine Window Seite wie gewohnt und Ihre Felder, um es hinzuzufügen wäre, sagen eine Label und TextBox Kontrolle in einem StackPanel:

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

Dann ein Standard Button für Submission erstellen (“ OK "oder" Abschicken ") und eine" Abbrechen "-Schaltfläche, wenn Sie möchten:

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

-Code-Behind
Hier finden Sie die Click Event-Handler-Funktionen im Code-Behind, fügen Sie aber, wenn Sie dort hin gehen, erstens, eine öffentliche Variable deklariert, wo Sie Ihre Textbox Wert gespeichert werden:

public static string strUserName = String.Empty; 

Dann, für die Event-Handler-Funktionen (mit der rechten Maustaste auf die Click Funktion auf der Schaltfläche XAML, wählen Sie "Gehe zu Definition", es wird für Sie erstellen), müssen Sie überprüfen, ob Ihre Box leer ist. Sie speichern es in der Variable, wenn sie nicht, und schließen Sie Ihre Fenster sind:

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."); 
} 

Es Aufruf von einer anderen Seite
Sie denken, wenn ich mit diesen this.Close() mein Fenster schließe dort oben, meinen Wert ist weg, oder? NEIN !! ich diese gefunden von einem anderen Standort aus: http://www.dreamincode.net/forums/topic/359208-wpf-how-to-make-simple-popup-window-for-input/

Sie ein ähnliches Beispiel dazu hatte (Ich reinigte es ein wenig nach oben), wie Ihr Window von einem anderen zu öffnen und die Werte abrufen:

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 
    } 
} 

Abbrechen Schaltfläche
Sie denken, gut, was ist mit der Schaltfläche Abbrechen? So fügen wir einfach eine andere öffentliche Variable zurück in unserem Pop-up-Fenster Code-Behind:

public static bool cancelled = false; 

Und lassen Sie uns unsere btnCancel_Click Event-Handler enthalten, und eine Änderung vornehmen zu 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."); 
} 

Und wir dann habe gerade gelesen, dass die Variable in unserem MainWindowbtnOpenPopup_Click Ereignisse:

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 
    } 
} 

Lange Antwort, aber ich wollte, wie leicht zeigen, Dies verwendet public static Variablen. No DialogResult, keine Rückgabewerte, nichts. Öffnen Sie einfach das Fenster, speichern Sie Ihre Werte mit den Button-Events im Popup-Fenster und rufen Sie diese anschließend im Hauptfenster ab.

+0

Es gibt eine Menge Weg, um den bereitgestellten Code zu verbessern: 1) Verwenden Sie nicht statisch zum Speichern von Daten, sonst werden Sie gelegentlich auf Probleme mit mehreren Dialogen stoßen; 2) es gibt DialogResult, um "true" über ShowDialog() zu übergeben; 3) IsCancel-Attribut für eine Schaltfläche macht es eine echte Abbrechen-Schaltfläche ohne zusätzlichen Code ... – AntonK

+0

@AntonK 1) Mit statischen Objekten können Sie Variablen in anderen Klassen aufrufen, ohne sie ständig instanziieren müssen. Statische Variablen schneiden mir das alles ab und sind weit vorzuziehen. Hatte nie ein Problem mit ihnen, weil sie jedes Mal zurückgesetzt werden, wenn das Objekt (Fenster, Seite) geöffnet ist, das sie geöffnet hat. Wenn Sie mehrere Dialoge erstellen möchten, erstellen Sie für jeden einen Dialog - verwenden Sie ihn nicht immer wieder oder ja, das ist problematisch - aber auch eine schlechte Kodierung, denn warum möchten Sie den gleichen Dialog 50 Mal? – vapcguy

+0

@AntonK 2) Sie können 'DialogResult' in WPF nicht zurückgeben, es ist' MessageBoxResult', was ich nur von Standard-Buttons in einem 'MessageBox.Show()' Dialog - nicht einem von einem benutzerdefinierten Dialog durch 'gefunden habe .ShowDialog() '- und kann nur nach den Standardoperatoren" MessageBoxResult.OK "," MessageBoxResult.Cancel "," Yes "," No "usw. abfragen - nicht boolesche Werte oder benutzerdefinierte Werte. 3) 'IsCancel' würde erfordern, es in einem Boolean zu speichern und das zurück zu senden, irgendwie, also war das eine Einheitslösung. – vapcguy

Verwandte Themen