Real Hint in TextBox Visual Studio C# [duplicate]

2019-05-23 16:54发布

This question already has an answer here:

I'm currently making a Windows Forms Application on Visual Studio in C# and I'm trying to find a way to have a real hint.

I've found a lot of answers online on how to have some text preset there, Some examples even show how to grey out the text to look like a placeholder, but that's not what I'm looking for.

I want a grayed out text that you don't have to backspace to type something there. So I want it to behave like an HTML placeholder like the "Search Q&A" search bar on stack Overflow.

Is there an easy way to do this, like configuring a property of the textbox in the designer on Visual Studio?

5条回答
叛逆
2楼-- · 2019-05-23 17:09

I know that this is an old question; However I was searching for a way and I found my answer to be best answer to display a prompt text in a TextBox:

1) Create a class .cs file called for example MyExtensions.cs having a namespace called for example 'Extensions'.

2) Create a method in the TextBox called Init(string prompt) that takes the prompt text you want to display inside the TextBox.

3) Let me stop talking and give you the rest of the code for MyExtensions.cs (The entire code):

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

}
}

Now Assume that you have three TextBox's : tbUsername, tbPassword, tbConfirm:

In your Form_Load(object sender, EventArgs e) method initialize your three TextBox's to have their appropriate Prompt Text Messages:

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

Enjoy! :)

查看更多
三岁会撩人
3楼-- · 2019-05-23 17:09

What about this

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

the this.ActiveControl = label1; is just to take focus away from the text box initially. If something else already does, don't worry about that line.

查看更多
贼婆χ
4楼-- · 2019-05-23 17:13

This might be the ugliest code but I think you can improve it.

This following class is merely an extension of the standard TextBox

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



        }


    }

Copy/paste to new cs file entitled PHTextBox.cs.

Go to your graphic designer and add a TextBox. Go to the designer and change the instiantion line for the textbox as follow:

enter image description here

Now compile but before you do, just make sure the textbox is not the first element to get the focus. Add button for that matter.

enter image description here

查看更多
祖国的老花朵
5楼-- · 2019-05-23 17:21

Please, take a look at my ControlHintManager class, ControlHintInfo type and ControlHintType enumeration. They are written in Vb.Net, but you can get the idea analyzing the source-code, or compile the library to use it in your C# project without any more effort.

My solution has even better behavior than the StackOverflows hint that you mentioned, taking into account that when the control leave focus, the hint-text should be restored if the string remains empty.

Usage is so friendlly:

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

ControlHintManager.SetHint(TextBox1, hint1);

To acchieve this by your own, one way is calling the Win32 SendMessage function with the EM_SETCUEBANNER message, however, that will produce a too basic hint with poor behavior, not recommendable,

so a proper way to acchieve this is by taking control of the edit-control text by yourself, handling the Control.HandleCreated, Control.Enter, Control.Leave, Control.MouseDown, Control.KeyDown and Control.Disposed events (as you can see in my linked source-code).

Just use a object to keep track of the control's state (forecolor, text, and optionally the font), then use properlly the event-handlers mentioned to set or restore the text and color.

This is a online C# translation of the most-important code of the linked urls if this help you understand it better:

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: It is Reflection based to support more variety of controls.

查看更多
该账号已被封号
6楼-- · 2019-05-23 17:25

Have you tried overlapping a label on the textbox?

On the textbox keypress event you can check the length of the textbox.text and set the label.

On the keypress event..

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

Of course you might want to set the default text of the label as well as grey it out too.

Issue with this is if your form is re sizable.

What you want to achieve is not native to windows forms.

查看更多
登录 后发表回答