.netwinformstextboxwatermark

Watermark TextBox in WinForms


Can anyone point me to a good implementation of a basic Windows Forms TextBox that will initially show watermark text that disappears when the cursor enters it? I think I can create my own with some creative use of Enter and Leave events, but I'm sure there's a perfectly usable implementation sitting around somewhere. I saw the WPF implementation and if necessary I could nest it, but a native WinForms TextBox derivative would be better.

I have this so far; haven't tried it yet but does anyone see any glaring problems?

public class WatermarkTextBox:TextBox
{
    public string WatermarkText { get; set; }

    public Color WatermarkColor { get; set; }

    private Color TextColor { get; set; }

    private bool isInTransition;

    public WatermarkTextBox()
    {
        WatermarkColor = SystemColors.GrayText;
    }

    private bool HasText { get { return Text.IsNotNullOrBlankOr(WatermarkText); }}

    protected override void OnEnter(EventArgs e)
    {
        base.OnEnter(e);

        if (HasText) return;

        isInTransition = true;
        ForeColor = TextColor;
        Text = String.Empty;
        isInTransition = false;
    }

    protected override void OnForeColorChanged(EventArgs e)
    {
        base.OnForeColorChanged(e);
        if (!isInTransition) //the change came from outside
            TextColor = ForeColor;
    }

    protected override void OnLeave(EventArgs e)
    {
        base.OnLeave(e);

        if (HasText) return;

        isInTransition = true;
        ForeColor = WatermarkColor;
        Text = WatermarkText.EmptyIfNull();
        isInTransition = false;
    }
}

EDIT: The above would have eventually worked with some finessing, but the CueProvider worked much better. Here's my final implementation:

public class WatermarkTextBox:TextBox
{
    private string watermarkText;
    public string WatermarkText
    {
        get { return watermarkText; }
        set
        {
            watermarkText = value;
            if (watermarkText.IsNullOrBlank())
                CueProvider.ClearCue(this);
            else
                CueProvider.SetCue(this, watermarkText);
        }
    }
}

I could have integrated the CueProvider functionality completely, but this works beautifully.


Solution

  • The official term is "cue banner". Here's another way to do it, just inheriting TextBox gets the job done too. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox and set the Cue property.

    You get a live preview of the Cue value in the designer, localized to the form's Language property. Lots of bang for very little buck, an excellent demonstration of the good parts of Winforms.

    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    class CueTextBox : TextBox {
        [Localizable(true)]
        public string Cue {
            get { return mCue; }
            set { mCue = value; updateCue(); }
        }
    
        private void updateCue() {
            if (this.IsHandleCreated && mCue != null) {
                SendMessage(this.Handle, 0x1501, (IntPtr)1, mCue);
            }
        }
        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
            updateCue();
        }
        private string mCue;
    
        // PInvoke
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, string lp);
    }
    

    UPDATE: now also available since .NETCore 3.0 (and .NET5 and up), they added the PlaceholderText property