【问题标题】:Real Hint in TextBox Visual Studio C# [duplicate]TextBox Visual Studio C#中的真实提示[重复]
【发布时间】:2016-07-22 16:11:32
【问题描述】:

我目前正在用 C# 在 Visual Studio 上制作一个 Windows 窗体应用程序,我正在尝试找到一种方法来获得真正的提示

我在网上找到了很多关于如何在其中预设一些文本的答案,有些示例甚至显示了如何将文本变灰以看起来像占位符,但这不是我想要的。

我想要一个灰显的文本,您无需退格即可在此处输入内容。所以我希望它表现得像一个 HTML 占位符就像堆栈溢出上的“搜索问答”搜索栏。

有没有一种简单的方法可以做到这一点,比如在 Visual Studio 的设计器中配置文本框的属性?

【问题讨论】:

  • 最好的办法是写一个System.Windows.Forms.TextBox类的扩展
  • 看到一个好的here。还支持多行,完全基于绘图,不使用Text属性,扩展性强。
  • 这里接受的答案的主要问题是:Text 属性即使用户不触摸它也会有价值。或者例如,当使用数据绑定时,当您为绑定到数字字段的文本框分配提示时会导致问题。或者将提示推送到数据源。对于如何显示提示,使用 Text 是一个非常糟糕的主意,您不应该为此目的使用 Text 属性。

标签: c# winforms textbox windows-forms-designer


【解决方案1】:

我知道这是一个老问题;但是我正在寻找一种方法,我发现我的答案是最佳答案TextBox中显示提示文本:

1) 创建一个 class .cs 文件,例如 MyExtensions.cs 具有 命名空间 em> 称为“扩展”。

2)TextBox 中创建一个名为 Init(string prompt) 的方法,该方法采用您要在其中显示的提示文本TextBox

3)我不说了,给你MyExtensions.cs的其余代码(整个代码):

MyExtensions.cs

using System.Drawing;
using System.Windows.Forms;

namespace Extensions
{
   public static class MyExtensions
{

    public static void Init(this TextBox textBox, string prompt)
    {
        textBox.Text = prompt;
        bool wma = true;
        textBox.ForeColor = Color.Gray;
        textBox.GotFocus += (source, ex) =>
        {
            if (((TextBox)source).ForeColor == Color.Black)
                return;
            if (wma)
            {
                wma = false;
                textBox.Text = "";
                textBox.ForeColor = Color.Black;
            }
        };

        textBox.LostFocus += (source, ex) =>
        {
            TextBox t = ((TextBox)source);
            if (t.Text.Length == 0)
            {
                t.Text = prompt;
                t.ForeColor = Color.Gray;
                return;
            }
            if (!wma && string.IsNullOrEmpty(textBox.Text))
            {
                wma = true;
                textBox.Text = prompt;
                textBox.ForeColor = Color.Gray;
            }
        };
        textBox.TextChanged += (source, ex) =>
        {
            if (((TextBox)source).Text.Length > 0)
            {
                textBox.ForeColor = Color.Black;
            }
        };
    }

}
}

现在假设您有三个TextBoxtbUsernametbPasswordtbConfirm

在您的 Form_Load(object sender, EventArgs e) 方法中初始化您的三个 TextBox 以使其具有相应的提示文本消息

using Extensions;

namespace MyApp{

         public partial class Form1 : Form{

                private void Form1_Load(object sender, 
                                        EventArgs e){

                    tbUsername.Init("Type a username");
                    tbPassword.Init("Type a password");
                    tbConfirm.Init("Confirm your password");
                }
        }
}

享受吧! :)

【讨论】:

  • 代码略有改动。对 LostFocus 的 if (t.Text.Length == 0) {...} 检查导致了一个错误。不错的解决方案!
【解决方案2】:

这可能是最丑的代码,但我认为你可以改进它。

下面这个类只是标准文本框的扩展

 class PHTextBox : System.Windows.Forms.TextBox
    {
        System.Drawing.Color DefaultColor; 
        public string PlaceHolderText {get;set;}
        public PHTextBox(string placeholdertext)
        {
            // get default color of text
           DefaultColor = this.ForeColor;
            // Add event handler for when the control gets focus
            this.GotFocus += (object sender, EventArgs e) => 
            {
                this.Text = String.Empty;
                this.ForeColor = DefaultColor;
            };

            // add event handling when focus is lost
            this.LostFocus += (Object sender, EventArgs e) => {
                if (String.IsNullOrEmpty(this.Text) || this.Text == PlaceHolderText)
                {
                    this.ForeColor = System.Drawing.Color.Gray;
                    this.Text = PlaceHolderText;
                }
                else
                {
                    this.ForeColor = DefaultColor;
                }
            };



            if (!string.IsNullOrEmpty(placeholdertext))
            {
                // change style   
                this.ForeColor = System.Drawing.Color.Gray;
                // Add text
                PlaceHolderText = placeholdertext;
                this.Text = placeholdertext;
            }



        }


    }

复制/粘贴到名为PHTextBox.cs的新cs文件。

转到您的图形设计师并添加一个文本框。 转到设计器并更改文本框的实例行如下:

现在编译,但在你编译之前,只要确保文本框不是第一个获得焦点的元素。为此添加按钮。

【讨论】:

  • 看一个好的here。它还支持多行,完全基于绘图,不使用Text属性,扩展性强。
  • 这里接受的答案的主要问题是:Text 属性即使用户不触摸它也会有价值。或者例如,当使用数据绑定时,当您为绑定到数字字段的文本框分配提示时会导致问题。或者它将提示推送到数据源。对于如何显示提示,使用 Text 是一个非常糟糕的主意,您不应该为此目的使用 Text 属性。
  • 与 reza 一致,但 text 属性可以被覆盖,因此当请求文本时,如果它等于占位符文本,它会变为 null。您可以根据自己的喜好对其进行编辑。
  • 如果 text 属性返回 null,则文本框中没有可显示的文本。
  • 我认为链接的帖子是一个很好且可扩展的实现,值得更多关注。试一试。希望对您有所帮助:)
【解决方案3】:

请看一下我的 ControlHintManager 类,ControlHintInfo 类型和 ControlHintType 枚举。它们是用 Vb.Net 编写的,但您可以轻松地分析源代码,或编译库以在您的 C# 项目中使用它。

我的解决方案比您提到的 StackOverflows 提示具有更好的行为,考虑到当控件离开焦点时,如果字符串保持为空,则提示文本应恢复。

使用非常友好:

ControlHintInfo hint1 = 
    new ControlHintInfo("I'm a hint text.", font (or nul), Color.Gray, 
                        ControlHintType.Persistent);

ControlHintManager.SetHint(TextBox1, hint1);

要自己实现这一点,一种方法是使用 EM_SETCUEBANNER 消息调用 Win32 SendMessage 函数,但是,这会产生过于基本的提示,行为不佳,不推荐,

因此,实现这一点的正确方法是自己控制编辑控制文本,处理 Control.HandleCreatedControl.EnterControl.LeaveControl.MouseDownControl.KeyDownControl.Disposed 事件(正如你在我的链接源代码中看到的那样)。

只需使用一个对象来跟踪控件的状态(前景色、文本和可选的字体),然后正确使用提到的事件处理程序来设置或恢复文本和颜色。

这是链接网址的最重要代码的在线 C# 翻译,如果这有助于您更好地理解它:

private static void Control_HandleCreated(object sender, EventArgs e) {

    InstanceControlHintFields();

    Control ctrl = (Control)sender;
    ControlHintInfo hintInfo = controlHintsB(ctrl);

    SetProperties(ctrl, hintInfo);
}

private static void Control_Enter(object sender, EventArgs e) {

    InstanceControlHintFields();

    Control ctrl = (Control)sender;
    string ctrlText = ctrl.Text;
    ControlHintInfo ctrlDefaults = controlHintsDefaults(ctrl);
    ControlHintInfo hintInfo = controlHintsB(ctrl);

    switch (hintInfo.HintType) {

        case ControlHintType.Normal:
            if ((ctrlText.Equals(hintInfo.Text, StringComparison.OrdinalIgnoreCase))) {
                RestoreProperties(ctrl, ctrlDefaults);
            }

            break;
    }
}

private static void Control_Leave(object sender, EventArgs e) {

    InstanceControlHintFields();

    Control ctrl = (Control)sender;
    string ctrlText = ctrl.Text;
    ControlHintInfo ctrlDefaults = controlHintsDefaults(ctrl);
    ControlHintInfo hintInfo = controlHintsB(ctrl);

    switch (hintInfo.HintType) {

        case ControlHintType.Normal:
            if ((ctrlText.Equals(hintInfo.Text, StringComparison.OrdinalIgnoreCase))) {
                RestoreProperties(ctrl, ctrlDefaults);

            } else if (string.IsNullOrEmpty(ctrlText)) {
                SetProperties(ctrl, hintInfo);

            }

            break;
        case ControlHintType.Persistent:
            if (string.IsNullOrEmpty(ctrlText)) {
                SetProperties(ctrl, hintInfo);
            }

            break;
    }
}

private static void Control_MouseDown(object sender, MouseEventArgs e) {

    InstanceControlHintFields();

    Control ctrl = (Control)sender;
    string ctrlText = ctrl.Text;
    ControlHintInfo hintInfo = controlHintsB(ctrl);

    switch (hintInfo.HintType) {

        case ControlHintType.Persistent:


            if ((ctrlText.Equals(hintInfo.Text, StringComparison.OrdinalIgnoreCase))) {
                // Get the 'Select' control's method (if exist).
                MethodInfo method = sender.GetType.GetMethod("Select", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, {
                    typeof(int),
                    typeof(int)
                }, null);

                if ((method != null)) {
                    // Select the zero length.
                    method.Invoke(ctrl, new object[] {
                        0,
                        0
                    });
                }

            }

            break;
    }
}

private static void Control_KeyDown(object sender, KeyEventArgs e) {

    Control ctrl = (Control)sender;
    string ctrlText = ctrl.Text;
    ControlHintInfo ctrlDefaults = controlHintsDefaults(ctrl);
    ControlHintInfo hintInfo = controlHintsB(ctrl);

    switch (hintInfo.HintType) {

        case ControlHintType.Persistent:
            if ((ctrlText.Equals(hintInfo.Text, StringComparison.OrdinalIgnoreCase))) {
                RestoreProperties(ctrl, ctrlDefaults);

            } else if (string.IsNullOrEmpty(ctrlText)) {
                RestoreProperties(ctrl, ctrlDefaults, skipProperties: { "Text" });

            }

            break;
        case ControlHintType.Normal:
            if (string.IsNullOrEmpty(ctrlText)) {
                RestoreProperties(ctrl, ctrlDefaults);
            }

            break;
    }
}

private static void Control_Disposed(object sender, EventArgs e) {
    RemoveHint((Control)sender);
}

PS:基于Reflection,支持更多种类的控件。

【讨论】:

    【解决方案4】:

    这个呢

        private bool hasTextBeenTyped;
    
        private void Form1_Load(object sender, EventArgs e)
        {
            this.ActiveControl = label1;
            textBox1.ForeColor = Color.LightGray;
        }
    
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            hasTextBeenTyped = !String.IsNullOrEmpty(textBox1.Text);
    
            if (hasTextBeenTyped)
            {
                textBox1.ForeColor = Color.Black;
            }
        }
    
        private void textBox1_Click(object sender, EventArgs e)
        {
            if (!hasTextBeenTyped)
            {
                textBox1.Text = "";
            }
        }
    
        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            hasTextBeenTyped = true;
        }
    

    this.ActiveControl = label1;只是最初将焦点从文本框移开。如果其他东西已经做了,不要担心那条线。

    【讨论】:

      【解决方案5】:

      您是否尝试过在文本框上重叠标签?

      在文本框按键事件中,您可以检查 textbox.text 的长度并设置标签。

      在按键事件中..

      MyLabel.Visible = String.IsNullOrEmpty(MyTextBox.Text);
      

      当然,您可能希望设置标签的默认文本以及将其变灰。

      问题在于您的表单是否可调整大小。

      您想要实现的不是 Windows 窗体原生的。

      【讨论】:

      • 这让我想到将提示放在文本框的标签属性中,然后在事件中使用
      猜你喜欢
      • 2011-05-11
      • 2018-11-29
      • 1970-01-01
      • 2018-03-02
      • 2017-06-28
      • 1970-01-01
      • 2014-10-01
      • 2013-10-19
      • 2011-02-01
      相关资源
      最近更新 更多