窗体应用程序中的提示对话框

141

我正在使用 System.Windows.Forms ,但奇怪的是我没有创建它们的能力。

我如何获得类似于JavaScript提示对话框的东西,而不使用JavaScript?

MessageBox很好,但用户无法输入任何内容。

我希望用户能够输入任何可能的文本输入。


你能否提供一个代码示例,说明你想要做什么? - Andrew Cooper
你需要什么样的输入?能否提供更多细节?CommonDialog看一下继承它的类,有没有合适的? - Sanjeevakumar Hiremath
27
有趣的是,有三个人要求楼主提供更多细节和代码示例,但是“像JavaScript提示对话框”这一点已经非常清楚了。 - Camilo Martin
2
以下是两个编程示例,一个基本示例,另一个带有输入验证:
  1. 基本示例 - http://www.csharp-examples.net/inputbox/
  2. 验证示例 - http://www.csharp-examples.net/inputbox-class/
- CodeMonkey
11个回答

325

您需要创建自己的提示对话框。您可以考虑创建一个类来实现此功能。

public static class Prompt
{
    public static string ShowDialog(string text, string caption)
    {
        Form prompt = new Form()
        {
            Width = 500,
            Height = 150,
            FormBorderStyle = FormBorderStyle.FixedDialog,
            Text = caption,
            StartPosition = FormStartPosition.CenterScreen
        };
        Label textLabel = new Label() { Left = 50, Top=20, Text=text };
        TextBox textBox = new TextBox() { Left = 50, Top=50, Width=400 };
        Button confirmation = new Button() { Text = "Ok", Left=350, Width=100, Top=70, DialogResult = DialogResult.OK };
        confirmation.Click += (sender, e) => { prompt.Close(); };
        prompt.Controls.Add(textBox);
        prompt.Controls.Add(confirmation);
        prompt.Controls.Add(textLabel);
        prompt.AcceptButton = confirmation;

        return prompt.ShowDialog() == DialogResult.OK ? textBox.Text : "";
    }
}

然后调用它:

string promptValue = Prompt.ShowDialog("Test", "123");

更新:

根据评论和另一个问题,添加了默认按钮(回车键)和初始焦点。


2
如何扩展此功能以实现A)添加取消按钮和B)在返回之前以某种方式验证文本字段中的文本? - ewok
1
@SeanWorle 我没有看到提到那个的地方。 - Bas
问题开头就说了:“我正在使用System.Windows.Forms,但奇怪的是没有能力创建它们。”根据这个问题,他没有创建一个Form对象的能力。 - Sean Worle
1
我通过添加以下内容实现了这个功能:prompt.AcceptButton = confirmation; - B. Clay Shannon-B. Crow Raven
1
为了处理用户通过关闭按钮取消提示并返回空字符串,我们已添加了相应的代码。 - Matthew Lock
显示剩余15条评论

62

在你的 C# 代码中添加对 Microsoft.VisualBasic 的引用:

string input = Microsoft.VisualBasic.Interaction.InputBox("Prompt", 
                       "Title", 
                       "Default", 
                       0, 
                       0);

添加引用:在项目资源管理器窗口中右键单击“引用”,然后选择“添加引用”,并在列表中选中 VisualBasic。


5
这句话的意思是:在命名空间 Microsoft.VisualBasic 中不存在 Interaction - Khalil Khalaf
1
这比自定义类解决方案稍微好一些,因为它支持高dpi屏幕。 - mark gamache
3
我知道使用定制解决方案可能会更好,但我正在寻找一个快速简便的解决方案,这是最好的选择。真的很感谢大家。 - Juano
InputBox是Interaction类上的一个方法;Interaction不是一个命名空间。@KhalilKhalaf - redtetrahedron

13

在 Windows Forms 中本身没有这样的东西。

您需要为此创建自己的表单或:

使用 Microsoft.VisualBasic 引用。

Inputbox 是带入 .Net 以保持与 VB6 兼容性的遗留代码 - 所以我建议不要这样做。


3
这适用于 Microsoft.VisualBasic.Compatibility 命名空间。Microsoft.VisualBasic 更多地是一组在 .Net 之上的帮助库,与 VB 没有特别的关系。 - Jim Wooley
-1是因为关于VB引用的不准确陈述。没有理由吓唬人们不使用这个非常有用的内置功能。 - StayOnTarget

9

从理论上讲,Bas的答案可能会使你陷入内存问题,因为ShowDialog不会被处理。我认为这是一种更合适的方式。此外,还要提到textLabel在处理较长文本时应该是可读的。

public class Prompt : IDisposable
{
    private Form prompt { get; set; }
    public string Result { get; }

    public Prompt(string text, string caption)
    {
        Result = ShowDialog(text, caption);
    }
    //use a using statement
    private string ShowDialog(string text, string caption)
    {
        prompt = new Form()
        {
            Width = 500,
            Height = 150,
            FormBorderStyle = FormBorderStyle.FixedDialog,
            Text = caption,
            StartPosition = FormStartPosition.CenterScreen,
            TopMost = true
        };
        Label textLabel = new Label() { Left = 50, Top = 20, Text = text, Dock = DockStyle.Top, TextAlign = ContentAlignment.MiddleCenter };
        TextBox textBox = new TextBox() { Left = 50, Top = 50, Width = 400 };
        Button confirmation = new Button() { Text = "Ok", Left = 350, Width = 100, Top = 70, DialogResult = DialogResult.OK };
        confirmation.Click += (sender, e) => { prompt.Close(); };
        prompt.Controls.Add(textBox);
        prompt.Controls.Add(confirmation);
        prompt.Controls.Add(textLabel);
        prompt.AcceptButton = confirmation;

        return prompt.ShowDialog() == DialogResult.OK ? textBox.Text : "";
    }

    public void Dispose()
    {
        //See Marcus comment
        if (prompt != null) { 
            prompt.Dispose(); 
        }
    }
}

实现:

using(Prompt prompt = new Prompt("text", "caption")){
    string result = prompt.Result;
}

2
良好的内存管理使用。但是,当添加取消按钮时,这会失败,因为此时“提示”为空。允许取消提示的简单修复方法是将“public void Dispose()”中的“prompt.Dispose();”替换为“if(prompt!= null){prompt.Dispose();}”。 - Marcus Parsons

6

通常情况下,将VisualBasic库导入C#程序并不是一个好主意(不是因为它们不能工作,而是出于兼容性,风格和升级能力的考虑),但是您可以调用Microsoft.VisualBasic.Interaction.InputBox()来显示所需的对话框。

如果您能够创建Windows.Forms对象,那将是最好的选择,但是您说您无法这样做。


30
为什么这不是一个好主意?可能会出现哪些“兼容性”和“升级能力”问题?就风格而言,大多数C#程序员都不愿使用来自名为“VisualBasic”的命名空间的类,但这只存在于他们的想象中,这种感觉并不存在实际上。同样可以把它命名为Microsoft.MakeMyLifeEasierWithAlreadyImplementedMethods命名空间。 - Cody Gray
3
一般而言,Microsoft.VisualBasic软件包旨在简化从VB 6升级代码。微软一直在威胁永久停用VB(尽管这可能永远不会发生),因此未来将无法保证支持该命名空间。此外,.NET的优点之一应该是可移植性——相同的代码将在安装了.NET框架的任何平台上运行。然而,Microsoft.VisualBasic并不能保证在任何其他平台上都可用(包括.NET移动端,在那里根本不可用)。 - Sean Worle
23
错误。那是 Microsoft.VisualBasic.Compatibility 子命名空间,而不是整个 VB.NET。很多“核心”功能都包含在 Microsoft.VisualBasic 命名空间中,它并不会消失。微软已经威胁要停用 VB 6,而不是 VB.NET。他们已经 反复 承诺它不会消失。一些人似乎仍然没有弄清楚其中的区别... - Cody Gray
1
这个答案最近得到了一些分数,所以引起了我的注意。我记得和 @CodyGray 的这次对话 - 也许我有点小气,但我想指出自从这次关于 Microsoft.VisualBasic 命名空间“不会消失”的讨论以来的几年里,在 .Net Core 和 Standard 中,Microsoft.VisualBasic.Interaction.InputBox() 已经不存在了。 - Sean Worle
它存在于Core 1、2、3.1上,可能也存在于.net standard中。但这并不意味着你应该使用它,尽管你可以这样做。我认为winForms在Core 5.0中不存在。 - Nick Turner

4
另一种方法是: 假设您有一个文本框输入类型, 创建一个表单,并将文本框的值作为公共属性。
public partial class TextPrompt : Form
{
    public string Value
    {
        get { return tbText.Text.Trim(); }
    }

    public TextPrompt(string promptInstructions)
    {
        InitializeComponent();

        lblPromptText.Text = promptInstructions;
    }

    private void BtnSubmitText_Click(object sender, EventArgs e)
    {
        Close();
    }

    private void TextPrompt_Load(object sender, EventArgs e)
    {
        CenterToParent();
    }
}

在主表单中,这将是代码:
var t = new TextPrompt(this, "Type the name of the settings file:");
t.ShowDialog()

使用这种方式,代码看起来更加简洁:

  1. 如果添加验证逻辑。
  2. 如果添加其他输入类型。

4

根据Bas Brekelmans的工作,我也创建了两个衍生物——"输入"对话框,可以让用户输入文本值和布尔值(TextBox和CheckBox):

public static class PromptForTextAndBoolean
{
    public static string ShowDialog(string caption, string text, string boolStr)
    {
        Form prompt = new Form();
        prompt.Width = 280;
        prompt.Height = 160;
        prompt.Text = caption;
        Label textLabel = new Label() { Left = 16, Top = 20, Width = 240, Text = text };
        TextBox textBox = new TextBox() { Left = 16, Top = 40, Width = 240, TabIndex = 0, TabStop = true };
        CheckBox ckbx = new CheckBox() { Left = 16, Top = 60, Width = 240, Text = boolStr };
        Button confirmation = new Button() { Text = "Okay!", Left = 16, Width = 80, Top = 88, TabIndex = 1, TabStop = true };
        confirmation.Click += (sender, e) => { prompt.Close(); };
        prompt.Controls.Add(textLabel);
        prompt.Controls.Add(textBox);
        prompt.Controls.Add(ckbx);
        prompt.Controls.Add(confirmation);
        prompt.AcceptButton = confirmation;
        prompt.StartPosition = FormStartPosition.CenterScreen;
        prompt.ShowDialog();
        return string.Format("{0};{1}", textBox.Text, ckbx.Checked.ToString());
    }
}

...以及选择多个选项之一(文本框和组合框)的文本:

public static class PromptForTextAndSelection
{
    public static string ShowDialog(string caption, string text, string selStr)
    {
        Form prompt = new Form();
        prompt.Width = 280;
        prompt.Height = 160;
        prompt.Text = caption;
        Label textLabel = new Label() { Left = 16, Top = 20, Width = 240, Text = text };
        TextBox textBox = new TextBox() { Left = 16, Top = 40, Width = 240, TabIndex = 0, TabStop = true };
        Label selLabel = new Label() { Left = 16, Top = 66, Width = 88, Text = selStr };
        ComboBox cmbx = new ComboBox() { Left = 112, Top = 64, Width = 144 };
        cmbx.Items.Add("Dark Grey");
        cmbx.Items.Add("Orange");
        cmbx.Items.Add("None");
        Button confirmation = new Button() { Text = "In Ordnung!", Left = 16, Width = 80, Top = 88, TabIndex = 1, TabStop = true };
        confirmation.Click += (sender, e) => { prompt.Close(); };
        prompt.Controls.Add(textLabel);
        prompt.Controls.Add(textBox);
        prompt.Controls.Add(selLabel);
        prompt.Controls.Add(cmbx);
        prompt.Controls.Add(confirmation);
        prompt.AcceptButton = confirmation;
        prompt.StartPosition = FormStartPosition.CenterScreen;
        prompt.ShowDialog();
        return string.Format("{0};{1}", textBox.Text, cmbx.SelectedItem.ToString());
    }
}

两者都需要相同的引用:

using System;
using System.Windows.Forms;

请按如下方式调用:
PromptForTextAndBoolean.ShowDialog("Jazz", "What text should accompany the checkbox?", "Allow Scat Singing"); 

PromptForTextAndSelection.ShowDialog("Rock", "What should the name of the band be?", "Beret color to wear");

2
Bas Brekelmans的答案非常简洁优雅。但是,在实际应用中我发现需要做一些改进,例如:
  • 当消息文本过长时自动调整表单大小。
  • 不要在屏幕中央自动弹出对话框。
  • 不提供用户输入验证。

这里的类可以解决上述限制: http://www.codeproject.com/Articles/31315/Getting-User-Input-With-Dialogs-Part-1

我只是下载了源代码并将InputBox.cs复制到我的项目中。

但是我还是很惊讶为什么没有更好的类似工具…… 我唯一的投诉是标题文本不支持换行,因为它使用了一个标签控件。


很好的回答,但是超出了所问问题的范围 - Munim Munna

2
不幸的是,在内置库中,C# 仍然没有提供这种功能。目前最好的解决方案是创建一个自定义类,并编写一个弹出小窗口的方法。 如果您正在使用 Visual Studio,可以通过单击“项目” > “添加类”来完成此操作。

Add Class

Visual C# 项目 > 代码 > 类 添加类2 将该类命名为 PopUpBox(如果需要,稍后可以重命名),并粘贴以下代码:
using System.Drawing;
using System.Windows.Forms;

namespace yourNameSpaceHere
{
    public class PopUpBox
    {
        private static Form prompt { get; set; }

        public static string GetUserInput(string instructions, string caption)
        {
            string sUserInput = "";
            prompt = new Form() //create a new form at run time
            {
                Width = 500, Height = 150, FormBorderStyle = FormBorderStyle.FixedDialog, Text = caption,
                StartPosition = FormStartPosition.CenterScreen, TopMost = true
            };
            //create a label for the form which will have instructions for user input
            Label lblTitle = new Label() { Left = 50, Top = 20, Text = instructions, Dock = DockStyle.Top, TextAlign = ContentAlignment.TopCenter };
            TextBox txtTextInput = new TextBox() { Left = 50, Top = 50, Width = 400 };

            ////////////////////////////OK button
            Button btnOK = new Button() { Text = "OK", Left = 250, Width = 100, Top = 70, DialogResult = DialogResult.OK };
            btnOK.Click += (sender, e) => 
            {
                sUserInput = txtTextInput.Text;
                prompt.Close();
            };
            prompt.Controls.Add(txtTextInput);
            prompt.Controls.Add(btnOK);
            prompt.Controls.Add(lblTitle);
            prompt.AcceptButton = btnOK;
            ///////////////////////////////////////

            //////////////////////////Cancel button
            Button btnCancel = new Button() { Text = "Cancel", Left = 350, Width = 100, Top = 70, DialogResult = DialogResult.Cancel };
            btnCancel.Click += (sender, e) => 
            {
                sUserInput = "cancel";
                prompt.Close();
            };
            prompt.Controls.Add(btnCancel);
            prompt.CancelButton = btnCancel;
            ///////////////////////////////////////

            prompt.ShowDialog();
            return sUserInput;
        }

        public void Dispose()
        {prompt.Dispose();}
    }
}

您需要将命名空间更改为您正在使用的内容。该方法返回一个字符串,因此以下是如何在调用方法中实现它的示例:
bool boolTryAgain = false;

do
{
    string sTextFromUser = PopUpBox.GetUserInput("Enter your text below:", "Dialog box title");
    if (sTextFromUser == "")
    {
        DialogResult dialogResult = MessageBox.Show("You did not enter anything. Try again?", "Error", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            boolTryAgain = true; //will reopen the dialog for user to input text again
        }
        else if (dialogResult == DialogResult.No)
        {
            //exit/cancel
            MessageBox.Show("operation cancelled");
            boolTryAgain = false;
        }//end if
    }
    else
    {
        if (sTextFromUser == "cancel")
        {
            MessageBox.Show("operation cancelled");
        }
        else
        {
            MessageBox.Show("Here is the text you entered: '" + sTextFromUser + "'");
            //do something here with the user input
        }

    }
} while (boolTryAgain == true);

该方法检查返回的字符串是否为文本值、空字符串或“cancel”(如果单击取消按钮,则getUserInput方法将返回“cancel”),并相应地采取行动。如果用户没有输入任何内容并单击了确定按钮,它将告诉用户并询问他们是否要取消或重新输入其文本。
附注: 在我的实现中,我发现所有其他答案都缺少以下1个或多个:
- 取消按钮 - 能够包含发送到方法的字符串中的符号 - 如何访问该方法并处理返回的值。
因此,我发布了自己的解决方案。希望有人能找到它有用。感谢Bas和Gideon +评论者对你们的贡献,你们帮助我想出了一个可行的解决方案!

1

这是我的重构版本,可以选择多行/单行

   public string ShowDialog(string text, string caption, bool isMultiline = false, int formWidth = 300, int formHeight = 200)
        {
            var prompt = new Form
            {
                Width = formWidth,
                Height = isMultiline ? formHeight : formHeight - 70,
                FormBorderStyle = isMultiline ? FormBorderStyle.Sizable : FormBorderStyle.FixedSingle,
                Text = caption,
                StartPosition = FormStartPosition.CenterScreen,
                MaximizeBox = isMultiline
            };

            var textLabel = new Label
            {
                Left = 10,
                Padding = new Padding(0, 3, 0, 0),
                Text = text,
                Dock = DockStyle.Top
            };

            var textBox = new TextBox
            {
                Left = isMultiline ? 50 : 4,
                Top = isMultiline ? 50 : textLabel.Height + 4,
                Multiline = isMultiline,
                Dock = isMultiline ? DockStyle.Fill : DockStyle.None,
                Width = prompt.Width - 24,
                Anchor = isMultiline ? AnchorStyles.Left | AnchorStyles.Top : AnchorStyles.Left | AnchorStyles.Right
            };

            var confirmationButton = new Button
            {
                Text = @"OK",
                Cursor = Cursors.Hand,
                DialogResult = DialogResult.OK,
                Dock = DockStyle.Bottom,
            };

            confirmationButton.Click += (sender, e) =>
            {
                prompt.Close();
            };

            prompt.Controls.Add(textBox);
            prompt.Controls.Add(confirmationButton);
            prompt.Controls.Add(textLabel);

            return prompt.ShowDialog() == DialogResult.OK ? textBox.Text : string.Empty;
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接