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.
On the Design tab, select Watermark > Custom Watermark. Choose Picture Watermark and select a picture, or choose Text watermark and type your watermark text in the Text box. Click OK.
Set the TextBoxWatermarkExtender properties TargetControlID=" ", WatermarkText=" ". The "TargetControlID" property specifies the TextBox id, on which you want to set the watermark text, and "WatermarkText" accepts the text as watermark for that TextBox.
Go to the xaml code behind and add the Namespace to it, so that we can use the class WatermarkHelper. And add the following two Grids inside the LayoutRoot Grid. And then add TextBlocks and TextBoxes to the Grid. TextBlock is for the Watermark text and TextBox is for user input.
The WinForms Watermark Text (banner text) Provider allows users to display watermark text for any edit control without requiring any additional customization. It supports clearing the watermark text when the control is in edit mode or when the control gets focus. The watermark text can be formatted by customizing the text color, font, and more.
Create 2 identical text boxes on a windows form. Name them "RealTextBox" (set tab index to 1) and "WatermarkTextBox" (set tab index to 0, set fore color to gray). Position WatermarkTextBox exactly on top of RealTextBox, so that the latter is not visible.
The watermark text can be formatted by customizing the text color, font, and more. They specify the rendering mode of the banner text. Focus Mode: The banner text disappears when the control gets focus.
You can use PlaceholderText property. It supports both multi-line and single-line text-box. If you look into the .NET CORE implementation of TextBox you see it's been implemented by handling paint message. It also shows the hint when MultiLine is true. It's based on handling WM_PAINT message and drawing the hint.
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); }
I've updated the answer given by @Hans Passant above to introduce constants, make it consistent with pinvoke.net definitions and to let the code pass FxCop validation.
class CueTextBox : TextBox { private static class NativeMethods { private const uint ECM_FIRST = 0x1500; internal const uint EM_SETCUEBANNER = ECM_FIRST + 1; [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, string lParam); } private string _cue; public string Cue { get { return _cue; } set { _cue = value; UpdateCue(); } } private void UpdateCue() { if (IsHandleCreated && _cue != null) { NativeMethods.SendMessage(Handle, NativeMethods.EM_SETCUEBANNER, (IntPtr)1, _cue); } } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); UpdateCue(); } }
Edit: update the PInvoke call to set CharSet
attribute, to err on the safe side. For more info see the SendMessage page at pinvoke.net.
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