0

I have a custom text box with placeholder effect. If the textbox is empty, the placeholder is shown.

When I pass the value of the textbox (when the textbox is empty and the placeholder is shown instead) to a function , it passes the placeholder value, but I want it to just pass an empty string.

enter image description here

I thought about overriding the Text property and do an internal check. Something like

public string Text
{
    get
    {
        if (this.Text == this.Placeholder)
        {
            return "";
        }
        return this.Text;
    }
    set
    {
        this.Text = value;
    }
}

but I don't know if this is possible. This would create an infinite loop, I think. How do I make this work?

I know I can use a custom property (e.g., ActualText instead of Text) to do this, but if it's possible, I'd like to use Text. If not, I'll use a custom property.

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

namespace CustomControls
{
    public class CustomTextBox : TextBox
    {
        private string _placeholder;

        public string Placeholder
        {
            get
            {
                return this._placeholder;
            }
            set
            {
                this._placeholder = value;
                if (value.IsEmpty(true))
                {
                    this._placeholder = "";
                }
                else
                {
                    this._placeholder = value;
                }
            }
        }

        public CustomTextBox()
        {
            Initialize();
        }

        private void Initialize()
        {
            this.Enter += new EventHandler(this.Placeholder_Hide);
            this.Leave += new EventHandler(this.Placeholder_Show);
        }

        // called from MainForm_Load
        public void InitPH()
        {
            if (!this.Placeholder.IsEmpty(true) && this.Text.IsEmpty())
            {
                this.Text = this.Placeholder;
                this.ForeColor = Color.Gray;
                this.Font = new Font("Segoe UI", 10.2F, FontStyle.Italic);
            }
        }

        private void Placeholder_Hide(object sender, EventArgs e)
        {
            if (this.Text == this._placeholder)
            {
                this.Text = "";
                this.ForeColor = Color.Black;
                this.Font = new Font("Segoe UI", 10.2F, FontStyle.Regular);
            }
        }

        private void Placeholder_Show(object sender, EventArgs e)
        {
            if (this.IsEmpty())
            {
                this.Text = this._placeholder;
                this.ForeColor = Color.Gray;
                this.Font = new Font("Segoe UI", 10.2F, FontStyle.Italic);
            }
        }

        public bool IsEmpty()
        {
            return this.Text.IsEmpty(true, this.Placeholder);
        }
    }
}
akinuri
  • 10,690
  • 10
  • 65
  • 102
  • 1
    @kblok I don't think the questions/problems are the same, but using "cue banner" solves my problem. I'm gonna drop my `CustomTextBox` and use what Han provided. – akinuri Jul 08 '17 at 16:17

2 Answers2

2

It would be best not to do if (this.Text == this._placeholder), because what if somebody actually entered the same text as the placeholder? It may be unlikely, but you don't want to leave in the possibility of unintended behavior.

One possible alternative is the following:

Add a field to your class, _valueIsSet, of type bool. Then, modify your event handlers to set it accordingly.

private void _valueIsSet = false;

private void Placeholder_Hide(object sender, EventArgs e)
{
    if (!this._valueIsSet)
    {
        this.Text = "";
        this.ForeColor = Color.Black;
        this.Font = new Font("Segoe UI", 10.2F, FontStyle.Regular);
    }
}

private void Placeholder_Show(object sender, EventArgs e)
{
    if (this.IsEmpty())
    {
        this._valueIsSet = false;
        this.Text = this._placeholder;
        this.ForeColor = Color.Gray;
        this.Font = new Font("Segoe UI", 10.2F, FontStyle.Italic);
    }
}

Then, add an event handler for your text box's KeyDown event:

private void customTextBox_KeyDown(object sender, KeyEventArgs e)
{
    this._valueIsSet = true;
}

Finally, create a property, myText:

public string myText
{
    get
    {
        return this._valueIsSet ? this.Text : null;
    }
}
stelioslogothetis
  • 9,371
  • 3
  • 28
  • 53
0

You can set a cue text on the TextBox that won't affect the Text property. See EM_SETCUEBANNER for more information.

Define the following on your Form

private const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);

Then in your Form Load

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    SendMessage(textBox1.Handle, EM_SETCUEBANNER, 0, "http://example.com");
}       
Mufaka
  • 2,333
  • 1
  • 18
  • 25