WPF:创建对话框/提示

发布于 2024-09-01 00:25:05 字数 219 浏览 12 评论 0原文

我需要创建一个对话框/提示,包括用于用户输入的文本框。我的问题是,确认对话框后如何获取文本?通常我会为此创建一个类,将文本保存在属性中。不过我想使用 XAML 设计对话框。因此,我必须以某种方式扩展 XAML 代码才能将 TextBox 的内容保存在属性中 - 但我想这对于纯 XAML 是不可能的。实现我想做的事情的最佳方式是什么?如何构建一个可以从 XAML 定义但仍然可以以某种方式返回输入的对话框?感谢您的任何提示!

I need to create a Dialog / Prompt including TextBox for user input. My problem is, how to get the text after having confirmed the dialog? Usually I would make a class for this which would save the text in a property. However I want do design the Dialog using XAML. So I would somehow have to extent the XAML Code to save the content of the TextBox in a property - but I guess that's not possible with pure XAML. What would be the best way to realize what I'd like to do? How to build a dialog which can be defined from XAML but can still somehow return the input? Thanks for any hint!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

长安忆 2024-09-08 00:25:05

“负责任”的答案是我建议为对话框构建一个 ViewModel 并在 TextBox 上使用双向数据绑定,以便 ViewModel 具有一些“ResponseText”属性或其他属性。这很容易做到,但可能有点矫枉过正。

务实的答案是只给你的文本框一个 x:Name ,以便它成为一个成员并将文本公开为你的代码隐藏类中的属性,如下所示:

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

The "responsible" answer would be for me to suggest building a ViewModel for the dialog and use two-way databinding on the TextBox so that the ViewModel had some "ResponseText" property or what not. This is easy enough to do but probably overkill.

The pragmatic answer would be to just give your text box an x:Name so that it becomes a member and expose the text as a property in your code behind class like so:

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

Then in your code behind...

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

Then to use it...

var dialog = new MyDialog();
if (dialog.ShowDialog() == true) {
    MessageBox.Show("You said: " + dialog.ResponseText);
}
弄潮 2024-09-08 00:25:05

编辑:可以使用 nuget https://www.nuget.org/packages/PromptDialog/

我只是添加一个静态方法来像 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);

Edit: Can be installed with nuget https://www.nuget.org/packages/PromptDialog/

I just add a static method to call it like a 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>

And the code behind:

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 you can call it like:

string repeatPassword = PromptDialog.Prompt("Repeat password", "Password confirm", inputType: PromptDialog.InputType.Password);
乱了心跳 2024-09-08 00:25:05

Josh 的出色回答,这一切都归功于他,但是我稍微修改了一下:

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 Behind

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

Great answer of Josh, all credit to him, I slightly modified it to this however:

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 Behind

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

And call it somewhere else

var dialog = new MyDialog("test", "hello");
dialog.Show();
dialog.Closing += (sender,e) =>
{
    var d = sender as MyDialog;
    if(!d.Canceled)
        MessageBox.Show(d.InputText);
}
我的鱼塘能养鲲 2024-09-08 00:25:05

您不需要任何这些其他花哨的答案。下面是一个简单的示例,它没有在 XAML 中设置所有 MarginHeightWidth 属性,但应该足以显示如何在基本层面上完成这项工作。

XAML
像平常一样构建一个 Window 页面并向其中添加字段,例如 StackPanel 内的 LabelTextBox 控件code>:

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

然后创建一个标准的按钮用于提交(“确定”或“提交”)和一个“取消”按钮(如果您愿意):

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

代码隐藏
您将在代码隐藏中添加 Click 事件处理函数,但是当您转到那里时,首先声明一个公共变量,用于存储文本框值:

public static string strUserName = String.Empty;

然后,对于事件处理函数 (右键单击按钮 XAML 上的 Click 函数,选择“转到定义”,它将为您创建它),您需要检查您的框是否为空。如果不是,则将其存储在变量中,然后关闭窗口:

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() 关闭窗口,我的值就消失了,对吗? 不!!我从另一个网站发现了这一点: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.");
}

然后我们只需在我们的 MainWindow btnOpenPopup_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,没有返回值,什么都没有。只需打开窗口,使用弹出窗口中的按钮事件存储您的值,然后在主窗口函数中检索它们。

You don't need ANY of these other fancy answers. Below is a simplistic example that doesn't have all the Margin, Height, Width properties set in the XAML, but should be enough to show how to get this done at a basic level.

XAML
Build a Window page like you would normally and add your fields to it, say a Label and TextBox control inside a StackPanel:

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

Then create a standard Button for Submission ("OK" or "Submit") and a "Cancel" button if you like:

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

Code-Behind
You'll add the Click event handler functions in the code-behind, but when you go there, first, declare a public variable where you will store your textbox value:

public static string strUserName = String.Empty;

Then, for the event handler functions (right-click the Click function on the button XAML, select "Go To Definition", it will create it for you), you need a check to see if your box is empty. You store it in your variable if it is not, and close your window:

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

Calling It From Another Page
You're thinking, if I close my window with that this.Close() up there, my value is gone, right? NO!! I found this out from another site: http://www.dreamincode.net/forums/topic/359208-wpf-how-to-make-simple-popup-window-for-input/

They had a similar example to this (I cleaned it up a bit) of how to open your Window from another and retrieve the values:

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

Cancel Button
You're thinking, well what about that Cancel button, though? So we just add another public variable back in our pop-up window code-behind:

public static bool cancelled = false;

And let's include our btnCancel_Click event handler, and make one change to 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.");
}

And then we just read that variable in our MainWindow btnOpenPopup_Click event:

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

Long response, but I wanted to show how easy this is using public static variables. No DialogResult, no returning values, nothing. Just open the window, store your values with the button events in the pop-up window, then retrieve them afterwards in the main window function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文