2010-05-09 3 views
61

Мне нужно создать диалог/приглашение, включая TextBox для ввода пользователем. Моя проблема в том, как получить текст после подтверждения диалога? Обычно я бы сделал класс для этого, который сохранил бы текст в свойстве. Однако я хочу, чтобы дизайн Dialog использовал XAML. Поэтому мне нужно каким-то образом расширить XAML-код, чтобы сохранить содержимое TextBox в свойстве, но я думаю, что это невозможно с чистым XAML. Какой был бы лучший способ понять, что я хотел бы сделать? Как создать диалог, который можно определить из XAML, но все же может каким-то образом вернуть вход? Спасибо за любой намек!WPF: создать диалог/приглашение

ответ

109

«Ответственный» ответ был бы для меня предлагать создать ViewModel для диалога и использовать двустороннюю привязку данных в TextBox, чтобы ViewModel имел свойство «ResponseText», а что нет. Это достаточно легко сделать, но, вероятно, пережить.

Прагматический ответ был бы просто дать ваш текстовое поле в х: Имя так, что он становится членом и выставить текст в качестве свойства в коде позади класса, как так:

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

Тогда в вашем код позади ...

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

Затем, чтобы использовать его ...

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

Большое спасибо Джошу и извините за мой поздний ответ! Вначале я слишком много внимания уделял загрузке XAML из файла, а не просто созданию класса, показанного вами. –

+2

+1 для указания прагматичного подхода :) – Jedidja

+6

Вам нужно обработать событие щелчка кнопки OK и установить this.DialogResult = true; для закрытия диалога и диалога dialog.ShowDialog() == true. –

15

Великий ответ Джоша, все кредит ему, я слегка изменил его к этому, однако:

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 код За

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

И называют это где-то еще

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

Вы должны заменить (в определении вашей сетки xaml) 50 * и 50 * на * и *, потому что нет необходимости в 50. – Mafii

24

Я просто добавить статический метод, называемый 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> 

И код позади:

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

Таким образом, вы можете назвать это нравится:

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

+1 Для реализации статического метода стиля MessageBox. Краткий, многоразовый код! –

+1

Как только я увидел слово «статический», я проигнорировал другие ответы. Спасибо! :) – maplemale

2

Вам не нужно ЛЮБОЙ этих других необычных ответов. Ниже приведен упрощенный пример, который не имеет всех свойств Margin, Height, Width, установленных в XAML, но должен быть достаточно, чтобы показать, как это сделать на базовом уровне.

XAML
Построить Window страницу, как вы обычно и добавить свои поля к нему, скажем, контроль Label и TextBox внутри StackPanel:

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

Затем создайте стандартную Button для представления (» OK "или" Отправить ") и кнопку« Отмена », если хотите:

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

Code-Behind
Вы добавите функции обработчика Click событий в коде-позади, но когда вы идете туда, первое, объявить открытую переменную, где вы будете хранить значение текстового поля:

public static string strUserName = String.Empty; 

Затем, для функций обработчика событий (щелкните правой кнопкой мыши функцию Click на кнопке XAML, выберите «Перейти к определению», она создаст ее для вас), вам нужна проверка, чтобы увидеть, пусто ли ваше поле. Вы храните его в переменной, если это не так, и закрыть окно:

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

вызова из другой страницы
Вы думаете, если я закрою окно с этим this.Close() там, мое значение ушел, правда? NO !! Я нашел это с другого сайта: http://www.dreamincode.net/forums/topic/359208-wpf-how-to-make-simple-popup-window-for-input/

Они имели подобный пример этого (я очистил его немного) о том, как открыть ваш Window от другого и получить значение:

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

Отмена кнопки
Вы думаете, ну а как насчет кнопки «Отмена»? Таким образом, мы просто добавим еще одну открытую переменную обратно в нашей всплывающем окне кода позади:

public static bool cancelled = false; 

И давайте включим наш btnCancel_Click обработчик события, и сделать одно изменение в 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."); 
} 

И тогда мы просто прочитать эту переменную в нашем 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 
    } 
} 

Длинный ответ, но я хотел показать, как легко это использует переменные public static. Нет DialogResult, никаких возвращаемых значений, ничего. Просто откройте окно, сохраните свои значения с помощью событий кнопки во всплывающем окне, а затем получите их в функции главного окна.

+0

Существует много способов улучшить предоставленный код: 1) не используйте статические данные для хранения данных, иначе вы иногда сталкиваетесь с проблемами с несколькими диалогами; 2) есть DialogResult для «передачи» истины через ShowDialog(); 3) Атрибут IsCancel для кнопки делает ее истинной кнопкой Отмена без дополнительного кода ... – AntonK

+0

@AntonK 1) Использование статических объектов - это то, как вы можете вызывать переменные в других классах, не создавая их все время. Для меня статические переменные вырезают все это и намного предпочтительнее. Никогда не было проблем с ними, потому что они будут сбрасываться в любое время, когда объект (Окно, Страница), в котором они есть, открывается. Если вам нужно несколько диалогов, создайте диалоговое окно для каждого из них - не используйте один и тот же один много раз или да, это проблематично, но также и плохое кодирование, потому что для чего вы хотите иметь тот же диалог 50 раз? – vapcguy

+0

@AntonK 2) Вы не можете передать «DialogResult» в WPF, это «MessageBoxResult», который я нашел только из стандартных кнопок в диалоговом окне «MessageBox.Show()», а не из пользовательского диалогового окна, .ShowDialog() '- и может запрашивать только стандартные операторы: MessageBoxResult.OK', MessageBoxResult.Cancel',« Да »,« Нет »и т. Д. - не логические или пользовательские значения. 3) 'IsCancel' потребовал бы хранить его в булевом языке и отправить его обратно, так или иначе, так что это было решение одного размера для всех. – vapcguy

Смежные вопросы