WPF:创建对话框/提示

WPF: Create a dialog / prompt

提问人:stefan.at.kotlin 提问时间:5/9/2010 最后编辑:Andrea Antonangelistefan.at.kotlin 更新时间:4/5/2021 访问量:133808

问:

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

WPF XAML 对话框 提示

评论


答:

154赞 Josh 5/9/2010 #1

“负责任”的答案是我建议为对话框构建一个 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);
}

评论

0赞 stefan.at.kotlin 7/6/2010
非常感谢乔希,很抱歉我回复晚了!我最初过于关注从文件加载 XAML,而不仅仅是创建您所示的类。
7赞 Erwin Mayer 10/11/2012
您需要处理 OK 按钮单击事件并设置此事件。DialogResult = 真;关闭对话框并拥有对话框。ShowDialog() == true。
1赞 vinsa 8/13/2019
我找到了一个很好的简单提示对话框,可以使用链接
0赞 Sirop4ik 2/5/2020
我在这里看到的一个问题,这个对话框也有最大按钮和最小迷宫按钮。是否可以禁用此按钮?
0赞 Tim 2/11/2020
@AlekseyTimoshchenko,由于这是一个普通的 Windows,因此可以使用属性 ResizeModeWindowStyle 来隐藏标题栏和/或最小化/最大化按钮。不过,我不知道您是否可以禁用它们。
17赞 xtds 7/3/2013 #2

乔希的好答案,全归功于他,我稍微修改了一下,但是:

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赞 Mafii 6/30/2016
应将(在网格定义 xaml 中)50* 和 50* 替换为 * 和 *,因为不需要 50。
2赞 solo 7/14/2019
提示:在窗口上设置使它看起来更漂亮。此外,并将其放置在父窗口的中心WindowStyle="ToolWindow"WindowStartupLocation="CenterOwner"dialog.Owner = this;
46赞 ManuelCanepa 7/23/2013 #3

编辑:可以与 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);

评论

7赞 Aaron Blenkush 8/21/2013
+1 用于实现样式的静态方法。简洁、可重用的代码!MessageBox
2赞 maplemale 1/4/2018
当我看到“静态”这个词时,我就忽略了其他答案。谢谢!:)
1赞 ManuelCanepa 4/5/2021
我制作了一个 nuget 包以包含在您的项目中:nuget.org/packages/PromptDialog
6赞 vapcguy 11/10/2016 #4

你不需要任何其他花哨的答案。下面是一个简单的示例,该示例没有在 XAML 中设置所有 、 、 属性,但应该足以演示如何在基本级别完成此操作。MarginHeightWidth

XAML
像往常一样构建一个页面,并将你的字段添加到其中,比如说 a 和 control inside a :
WindowLabelTextBoxStackPanel

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

然后,如果喜欢,请为提交创建一个标准(“确定”或“提交”)和一个“取消”按钮:Button

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

从另一个页面
调用它 你在想,如果我把窗户关上,我的价值就消失了,对吧?不!!我从另一个网站发现了这一点:http://www.dreamincode.net/forums/topic/359208-wpf-how-to-make-simple-popup-window-for-input/
this.Close()

他们有一个类似的例子(我清理了一下)如何从另一个打开你的并检索值: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_ClickbtnSubmit_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 staticDialogResult

评论

0赞 AntonK 6/27/2017
有很多方法可以改进提供的代码:1)不要使用静态来存储数据,否则你偶尔会遇到几个对话框的问题;2)有DialogResult通过ShowDialog()“传递”“'true';3) 按钮的 IsCancel 属性使其成为真正的取消按钮,无需任何额外代码......
0赞 vapcguy 6/29/2017
@AntonK 1) 使用静态对象是调用其他类中的变量而不必一直实例化它们的方法。对我来说,静态变量可以消除所有这些,并且更可取。它们从来没有问题,因为只要打开具有它们的对象(窗口、页面),它们就会被重置。如果你想要几个对话框,为每个对话框创建一个对话框 - 不要一遍又一遍地使用同一个对话框,或者是的,这是有问题的 - 但编码也很糟糕,因为你为什么要同一个对话框 50 次?
0赞 vapcguy 6/29/2017
@AntonK 2)你不能在WPF中传回,我发现它只适用于对话框上的标准按钮 - 而不是显示的自定义对话框中的按钮 - 并且只能查询标准运算符,,,“是”,“否”等 - 而不是布尔值或自定义值。3)无论如何,都需要将其存储在布尔值中并将其发回,因此这是一个一刀切的解决方案。DialogResultMessageBoxResultMessageBox.Show().ShowDialog()MessageBoxResult.OKMessageBoxResult.CancelIsCancel