4

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?

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Jon Spalding
  • 69
  • 1
  • 3
  • 9
  • the best way is to write an extension of the class System.Windows.Forms.TextBox – Amen Jlili Apr 03 '16 at 01:01
  • See a good one [here](http://stackoverflow.com/a/36534068/3110834). It also supports multi-line, it's completely based on drawing and doesn't use `Text` property and it's highly extensible. – Reza Aghaei Apr 10 '16 at 18:55
  • The main problem with the accepted answer here is: The `Text` property will have value even if user doesn't touch it. Or for example when using data-binding it causes problems when you assign a hint to the textboxes which are bound to number fields. Or it pushed hint to data source. Using the `Text` is a really bad idea about how to show a hint, you should not use `Text` property for this purpose. – Reza Aghaei Apr 10 '16 at 19:15

5 Answers5

4

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

Amen Jlili
  • 1,884
  • 4
  • 28
  • 51
  • 1
    See a good one [here](http://stackoverflow.com/a/36534068/3110834). It also supports multi-line, it's completely based on drawing and doesn't use `Text` property and it's highly extensible. – Reza Aghaei Apr 10 '16 at 18:54
  • 1
    The main problem with the accepted answer here is: The `Text` property will have value even if user doesn't touch it. Or for example when using data-binding it causes problems when you assign a hint to the textboxes which are bound to number fields. Or it pushed hint to data source. Using the `Text` is a really bad idea about how to show a hint, you should not use `Text` property for this purpose. – Reza Aghaei Apr 10 '16 at 19:16
  • iagree with reza but the text property can be overridden so when the text is requested it goes null if it equals to the placerholder text. you can edit it to your delight. – Amen Jlili Apr 10 '16 at 19:55
  • If you return null for text property, then there is no text to show in the text box. – Reza Aghaei Apr 10 '16 at 20:00
  • I think the linked post is a good and extensible implementation which deserves more attention. Give it a try. Hope you find it helpful :) – Reza Aghaei Apr 10 '16 at 20:03
  • @RezaAghaei The answer draws something over the textbox? isn't a little different from a placerholder. If you'd like to post on to update your answer, i'll upvote it so you feel less grudgy! :) – Amen Jlili Apr 10 '16 at 20:13
  • Drawing is base of of all thing that you see on windows forms. Even the text which you see in the text box is a drawing. And also a hint is a drawing, if you see it in action you will see it's the best option. – Reza Aghaei Apr 10 '16 at 20:19
  • sure i will bookmark your answer for future references thanks for the info – Amen Jlili Apr 10 '16 at 20:21
  • & Thank you for your offer, I removed my post here and posted in main thread for watermark/cue/hint for text box to be more useful for more future readers. But, it's not about grudge, it's about sharing knowledge and posting a good answer :) – Reza Aghaei Apr 10 '16 at 20:24
  • keep up the good spirit ! – Amen Jlili Apr 10 '16 at 20:27
1

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.

jegtugado
  • 5,081
  • 1
  • 12
  • 35
1

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

Alan Deep
  • 2,037
  • 1
  • 14
  • 22
0

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.

JimDel
  • 4,309
  • 11
  • 54
  • 99
0

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.

ElektroStudios
  • 19,105
  • 33
  • 200
  • 417