Displaying "Type here to ..." until the user enters text into a TextBox
is a well-known usability feature nowadays. How would one implement this feature in C#?
My idea is to override OnTextChanged
, but the logic to handle the changes of text from and to "Type here" is a bit tricky...
Displaying "Type here" on initialization and removing it on first input is easy, but I want to display the message every time the entered text becomes empty.
Step 1: Create a windows form. Step 2: Drag the TextBox control from the ToolBox and Drop it on the windows form. You can place TextBox anywhere on the windows form according to your need. Step 3: After drag and drop you will go to the properties of the TextBox control to set the Text property of the TextBox.
To add a button and a text box Verify that the document is open in the Visual Studio designer. From the Common Controls tab of the Toolbox, drag a TextBox control to the document. In Word, controls are dropped in-line with text by default.
Something that has worked for me:
this.waterMarkActive = true; this.textBox.ForeColor = Color.Gray; this.textBox.Text = "Type here"; this.textBox.GotFocus += (source, e) => { if (this.waterMarkActive) { this.waterMarkActive = false; this.textBox.Text = ""; this.textBox.ForeColor = Color.Black; } }; this.textBox.LostFocus += (source, e) => { if (!this.waterMarkActive && string.IsNullOrEmpty(this.textBox.Text)) { this.waterMarkActive = true; this.textBox.Text = "Type here"; this.textBox.ForeColor = Color.Gray; } };
Where bool waterMarkActive
is a class member variable and textBox
is the TextBox
. This probably should be encapsulated though :) There might be some issues with this approach, but I'm not currently aware of any.
I recently discovered that Windows support water marks in text boxes; they are called cue banners (see here). It's very easy to implement:
// Within your class or scoped in a more appropriate location: [DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); // In your constructor or somewhere more suitable: SendMessage(textBox.Handle, 0x1501, 1, "Please type here.");
Where textBox
is an instance of TextBox
, 0x1501
is the code for the windows message EM_SETCUEBANNER
, the wParam
may either be TRUE
(non-zero) or FALSE
(zero), and lParam
is the water mark you'd like to display. wParam
indicates when the cue banner should be displayed; if set to TRUE
then the cue banner will be displayed even when the control has focus.
What you're looking for is a TextBox with a "watermark".
There's a sample implementation for C# here, all credits to Wael Alghool.
The relevant part of his code is:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing; namespace wmgCMS { class WaterMarkTextBox : TextBox { private Font oldFont = null; private Boolean waterMarkTextEnabled = false; #region Attributes private Color _waterMarkColor = Color.Gray; public Color WaterMarkColor { get { return _waterMarkColor; } set { _waterMarkColor = value; Invalidate();/*thanks to Bernhard Elbl for Invalidate()*/ } } private string _waterMarkText = "Water Mark"; public string WaterMarkText { get { return _waterMarkText; } set { _waterMarkText = value; Invalidate(); } } #endregion //Default constructor public WaterMarkTextBox() { JoinEvents(true); } //Override OnCreateControl ... thanks to "lpgray .. codeproject guy" protected override void OnCreateControl() { base.OnCreateControl(); WaterMark_Toggel(null, null); } //Override OnPaint protected override void OnPaint(PaintEventArgs args) { // Use the same font that was defined in base class System.Drawing.Font drawFont = new System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit); //Create new brush with gray color or SolidBrush drawBrush = new SolidBrush(WaterMarkColor);//use Water mark color //Draw Text or WaterMark args.Graphics.DrawString((waterMarkTextEnabled ? WaterMarkText : Text), drawFont, drawBrush, new PointF(0.0F, 0.0F)); base.OnPaint(args); } private void JoinEvents(Boolean join) { if (join) { this.TextChanged += new System.EventHandler(this.WaterMark_Toggel); this.LostFocus += new System.EventHandler(this.WaterMark_Toggel); this.FontChanged += new System.EventHandler(this.WaterMark_FontChanged); //No one of the above events will start immeddiatlly //TextBox control still in constructing, so, //Font object (for example) couldn't be catched from within //WaterMark_Toggle //So, call WaterMark_Toggel through OnCreateControl after TextBox //is totally created //No doupt, it will be only one time call //Old solution uses Timer.Tick event to check Create property } } private void WaterMark_Toggel(object sender, EventArgs args ) { if (this.Text.Length <= 0) EnableWaterMark(); else DisbaleWaterMark(); } private void EnableWaterMark() { //Save current font until returning the UserPaint style to false (NOTE: //It is a try and error advice) oldFont = new System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit); //Enable OnPaint event handler this.SetStyle(ControlStyles.UserPaint, true); this.waterMarkTextEnabled = true; //Triger OnPaint immediatly Refresh(); } private void DisbaleWaterMark() { //Disbale OnPaint event handler this.waterMarkTextEnabled = false; this.SetStyle(ControlStyles.UserPaint, false); //Return back oldFont if existed if(oldFont != null) this.Font = new System.Drawing.Font(oldFont.FontFamily, oldFont.Size, oldFont.Style, oldFont.Unit); } private void WaterMark_FontChanged(object sender, EventArgs args) { if (waterMarkTextEnabled) { oldFont = new System.Drawing.Font(Font.FontFamily,Font.Size,Font.Style, Font.Unit); Refresh(); } } } }
Based on @Pooven's answer (thank you!), I created this class. Works for me.
/// <summary>
/// A textbox that supports a watermak hint.
/// </summary>
public class WatermarkTextBox : TextBox
{
/// <summary>
/// The text that will be presented as the watermak hint
/// </summary>
private string _watermarkText = "Type here";
/// <summary>
/// Gets or Sets the text that will be presented as the watermak hint
/// </summary>
public string WatermarkText
{
get { return _watermarkText; }
set { _watermarkText = value; }
}
/// <summary>
/// Whether watermark effect is enabled or not
/// </summary>
private bool _watermarkActive = true;
/// <summary>
/// Gets or Sets whether watermark effect is enabled or not
/// </summary>
public bool WatermarkActive
{
get { return _watermarkActive; }
set { _watermarkActive = value; }
}
/// <summary>
/// Create a new TextBox that supports watermak hint
/// </summary>
public WatermarkTextBox()
{
this._watermarkActive = true;
this.Text = _watermarkText;
this.ForeColor = Color.Gray;
GotFocus += (source, e) =>
{
RemoveWatermak();
};
LostFocus += (source, e) =>
{
ApplyWatermark();
};
}
/// <summary>
/// Remove watermark from the textbox
/// </summary>
public void RemoveWatermak()
{
if (this._watermarkActive)
{
this._watermarkActive = false;
this.Text = "";
this.ForeColor = Color.Black;
}
}
/// <summary>
/// Applywatermak immediately
/// </summary>
public void ApplyWatermark()
{
if (!this._watermarkActive && string.IsNullOrEmpty(this.Text)
|| ForeColor == Color.Gray )
{
this._watermarkActive = true;
this.Text = _watermarkText;
this.ForeColor = Color.Gray;
}
}
/// <summary>
/// Apply watermak to the textbox.
/// </summary>
/// <param name="newText">Text to apply</param>
public void ApplyWatermark(string newText)
{
WatermarkText = newText;
ApplyWatermark();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With