Watermark TextBox no WinForms

Alguém pode me apontar para uma boa implementação de um Windows Forms TextBox básico que mostrará inicialmente o texto de marca d’água que desaparece quando o cursor entra nele? Eu acho que posso criar o meu próprio com algum uso criativo de events Enter e Leave, mas tenho certeza que há uma implementação perfeitamente utilizável em algum lugar. Eu vi a implementação do WPF e, se necessário, eu poderia aninhá-lo, mas um derivado nativo WinForms TextBox seria melhor.

Eu tenho isso até agora; não tentei ainda, mas alguém vê algum problema gritante?

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: O acima teria eventualmente trabalhado com alguma finessing, mas o CueProvider funcionou muito melhor. Aqui está minha implementação 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); } } } 

Eu poderia ter integrado a funcionalidade do CueProvider completamente, mas isso funciona lindamente.

O termo oficial é “cue banner”. Aqui está outra maneira de fazer isso, apenas herdar o TextBox também faz o trabalho. Adicione uma nova class ao seu projeto e cole o código mostrado abaixo. Compilar. Solte o novo controle da parte superior da checkbox de ferramentas e defina a propriedade Cue.

Você obtém uma visualização ao vivo do valor de Cue no designer, localizado na propriedade Language do formulário. Muito barulho por muito pouco dinheiro, uma excelente demonstração das partes boas 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); } 

Eu atualizei a resposta dada pelo @Hans Passant acima para introduzir constantes, torná-las consistentes com as definições do pinvoke.net e permitir que o código passe na validação do 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(); } } 

Edit: atualizar a chamada PInvoke para definir o atributo CharSet , para errar no lado seguro. Para mais informações, consulte a página SendMessage em pinvoke.net .

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

E as constantes da mensagem:

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

E a melhor maneira de implementá-lo é como um método de extensão.
Então, para o controle TextBox, a syntax seria:

 MyTextBox.CueBanner(false, "Password"); 

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

Aqui está uma implementação de um TextBox que suporta a exibição de dicas (ou marca d’água ou sugestão):

  • Também mostra a dica quando o MultiLine é verdadeiro.
  • Ele é baseado no tratamento da mensagem WM_PAINT e na sugestão. Assim, você pode simplesmente personalizar a dica e adicionar algumas propriedades, como a cor da dica, ou pode desenhar da direita para a esquerda ou controlar quando mostrar a dica.
 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); } } } } } 

Se você usar EM_SETCUEBANNER , haverá dois problemas. O texto sempre será mostrado em uma cor padrão do sistema. Além disso, o texto não será mostrado quando o TextBox for MultiLine .

Usando a solução de pintura, você pode mostrar o texto com qualquer cor que desejar. Você também pode mostrar a marca d’água quando o controle é multi-linha:

insira a descrição da imagem aqui

Baixar

Você pode clonar ou baixar o exemplo de trabalho:

  • Baixar Zip
  • Repositório Github

Você pode adicionar uma marca d’água a uma checkbox de texto (multilinha ou não) que funciona muito bem desenhando-a em diferentes controles do evento Paint. Por exemplo:

  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 

Faça com que o texto padrão da checkbox de texto seja o que você quiser que a marca d’água seja. Suponho que neste exemplo você nomeie a checkbox de texto txtWatermark

Eu sou novo. Me desculpe se eu terrivelmente estraguei o post … Eu também não tenho idéia se isso funciona …