Marca de agua TextBox en WinForms

¿Alguien puede indicarme una buena implementación de un TextBox de Windows Forms básico que inicialmente mostrará un texto de marca de agua que desaparece cuando el cursor entra en él? Creo que puedo crear el mío con un uso creativo de los eventos Enter y Leave, pero estoy seguro de que hay una implementación perfectamente utilizable en algún lugar. Vi la implementación de WPF y, si es necesario, pude anidarla, pero un derivado de WinForms TextBox nativo sería mejor.

Tengo esto hasta ahora; aún no lo he probado, pero ¿alguien ve problemas evidentes?

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; } } 

EDITAR: Lo anterior eventualmente habría funcionado con algunas finiseing, pero el CueProvider funcionó mucho mejor. Aquí está mi implementación final:

 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); } } } 

Podría haber integrado la funcionalidad CueProvider por completo, pero esto funciona maravillosamente.

El término oficial es “señal de aviso”. Aquí hay otra manera de hacerlo, simplemente heredando TextBox hace el trabajo también. Agregue una nueva clase a su proyecto y pegue el código que se muestra a continuación. Comstackr. Suelte el nuevo control desde la parte superior de la caja de herramientas y configure la propiedad Cue.

Obtiene una vista previa en vivo del valor Cue en el diseñador, localizado en la propiedad Idioma del formulario. Mucho dinero por muy poco dinero, una excelente demostración de las buenas partes de 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); } 

He actualizado la respuesta dada por @Hans Passant anterior para introducir constantes, hacerlo coherente con las definiciones de pinvoke.net y permitir que el código pase la validación de FxCop.

 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(); } } 

Editar: actualice la llamada PInvoke para establecer el atributo CharSet , para errar en el lado seguro. Para obtener más información, consulte la página SendMessage en pinvoke.net .

 [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam); 

Y las constantes del mensaje:

 private const uint EM_SETCUEBANNER = 0x1501; private const uint CB_SETCUEBANNER = 0x1703; // minimum supported client Windows Vista, minimum supported server Windows Server 2008 

Y en mi opinión, la mejor manera de implementarlo es como un método de extensión.
Entonces, para el control TextBox, la syntax sería:

 MyTextBox.CueBanner(false, "Password"); 

Del código:

 public static void CueBanner(this TextBox textbox, bool showcuewhenfocus, string cuetext) { uint BOOL = 0; if (showcuewhenfocus == true) { BOOL = 1; } SendMessage(textbox.Handle, EM_SETCUEBANNER, (IntPtr)BOOL, cuetext); ; } 

Aquí hay una implementación de un TextBox que admite mostrar sugerencia (o marca de agua o señal):

  • También muestra la sugerencia cuando MultiLine es verdadero.
  • Se basa en el manejo del mensaje WM_PAINT y el dibujo de la sugerencia. De modo que puede personalizar la sugerencia y agregar algunas propiedades como el color de sugerencia, o puede dibujarlo de derecha a izquierda o controlar cuándo mostrar la sugerencia.
 using System.Drawing; using System.Windows.Forms; public class ExTextBox : TextBox { string hint; public string Hint { get { return hint; } set { hint = value; this.Invalidate(); } } protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == 0xf) { if (!this.Focused && string.IsNullOrEmpty(this.Text) && !string.IsNullOrEmpty(this.Hint)) { using (var g = this.CreateGraphics()) { TextRenderer.DrawText(g, this.Hint, this.Font, this.ClientRectangle, SystemColors.GrayText , this.BackColor, TextFormatFlags.Top | TextFormatFlags.Left); } } } } } 

Si usa EM_SETCUEBANNER , habrá 2 problemas. El texto siempre se mostrará en un color predeterminado del sistema. Además, el texto no se mostrará cuando TextBox sea MultiLine .

Usando la solución de pintura, puede mostrar el texto con cualquier color que desee. También puede mostrar la marca de agua cuando el control es multilínea:

enter image description here

Descargar

Puede clonar o descargar el ejemplo de trabajo:

  • Descargar Zip
  • Repositorio de Github

Puede agregar una marca de agua a un cuadro de texto (de varias líneas o no) que funcione bastante bien dibujándolo en diferentes controles. Pinte evento. Por ejemplo:

  Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint If TextBox1.Text = "" Then TextBox1.CreateGraphics.DrawString("Enter Text Here", Me.Font, New SolidBrush(Color.LightGray), 0, 0) End If End Sub 

-OO-

 Private Sub randomSubName() Handles txtWatermark.Click txtWatermark.text = "" End Sub 

Haga que el texto predeterminado del cuadro de texto sea el que quiera que sea la marca de agua, supongo que en este ejemplo debe nombrar el cuadro de texto txtWatermark

Hola, soy nuevo. Lo siento si arruiné terriblemente la publicación … Tampoco tengo idea si esto funciona …