Watermark TextBox in WinForms

前端 未结 10 1841
说谎
说谎 2020-11-22 00:35

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 ca

相关标签:
10条回答
  • 2020-11-22 01:15

    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.

    0 讨论(0)
  • 2020-11-22 01:19
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace PlaceHolderTextBoxCSharp
    {
        public class CTextBox : TextBox
        {
            private Panel contenedor;
            protected string texto = "PlaceHolderText";
            protected Color colorTextoDefault = Color.Gray;
            public Color colorTexto = Color.Gray;
            protected Color colorTextoObligatorio = Color.Red;
            private Font fuente;
            private SolidBrush establecerColorTexto;
            private bool obligatoriedad = false;
            private bool colorConFoco = false;
            private int vuelta = 0;
    
            public CTextBox()
            {
                Inicializar();
            }
    
            private void Inicializar()
            {
                fuente = Font;
                CharacterCasing = CharacterCasing.Upper;
                contenedor = null;
    
                MuestraPlaceHolder();
    
                Leave += new EventHandler(PierdeFoco);
                TextChanged += new EventHandler(CambiaTexto);
            }
    
            private void EliminaPlaceHolder()
            {
                if (contenedor != null)
                {
                    Controls.Remove(contenedor);
                    contenedor = null;
                }
            }
    
            private void MuestraPlaceHolder()
            {
                if (contenedor == null && TextLength <= 0)
                {
                    contenedor = new Panel();
                    contenedor.Paint += new PaintEventHandler(contenedorPaint);
                    contenedor.Invalidate();
                    contenedor.Click += new EventHandler(contenedorClick);
                    Controls.Add(contenedor);
                }
            }
    
            private void contenedorClick(object sender, EventArgs e)
            {
                Focus();
            }
    
            private void contenedorPaint(object sender, PaintEventArgs e)
            {
                contenedor.Location = new Point(2, 0);
                contenedor.Height = Height;
                contenedor.Width = Width;
                contenedor.Anchor = AnchorStyles.Left | AnchorStyles.Right;
                establecerColorTexto = new SolidBrush(colorTexto);
                Graphics g = e.Graphics;
                g.DrawString(texto, fuente, establecerColorTexto, new PointF(-1f, 1f));
            }
    
            private void PierdeFoco(object sender, EventArgs e)
            {
                if (TextLength > 0)
                {
                    EliminaPlaceHolder();
                }
                else
                {
                    if (obligatoriedad == true)
                    {
                        colorTexto = colorTextoObligatorio;
                    }
                    else
                    {
                        colorTexto = colorTextoDefault;
                    }
    
                    Invalidate();
                }
            }
    
            private void CambiaTexto(object sender, EventArgs e)
            {
                if (TextLength > 0)
                {
                    EliminaPlaceHolder();
                }
                else
                {
                    MuestraPlaceHolder();
    
                    vuelta += 1;
    
                    if (vuelta >= 1 && obligatoriedad == true)
                    {
                        colorTexto = colorTextoObligatorio;
                    }
                }
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                MuestraPlaceHolder();
            }
    
            protected override void OnInvalidated(InvalidateEventArgs e)
            {
                base.OnInvalidated(e);
    
                if (contenedor != null)
                {
                    contenedor.Invalidate();
                }
            }
    
            [Category("Atributos PlaceHolder")]
            [Description("Establece el texto a mostrar.")]
    
            public string PlaceHolderText
            {
                get
                {
                    return texto;
                }
                set
                {
                    texto = value;
                    Invalidate();
                }
            }
    
            [Category("Atributos PlaceHolder")]
            [Description("Establece el estilo de fuente del PlaceHolder.")]
    
            public Font PlaceHolderFont
            {
                get
                {
                    return fuente;
                }
                set
                {
                    fuente = value;
                    Invalidate();
                }
            }
    
            [Category("Atributos PlaceHolder")]
            [Description("Indica si el campo es obligatorio.")]
    
            public bool PlaceHolderFieldRequired
            {
                get
                {
                    return obligatoriedad;
                }
                set
                {
                    obligatoriedad = value;
                    Invalidate();
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 01:21
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);
    

    And the message constants:

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

    And imho the best way to implement it is as an extension method.
    So for the TextBox control the syntax would be:

    MyTextBox.CueBanner(false, "Password");
    

    From the code:

    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); ;
    }
    
    0 讨论(0)
  • 2020-11-22 01:23

    With .Net Core 3 a property was introduced into TextBox: PlaceHolderText

    If one is going to need this in a FrameWork application the required code parts can be taken from the official open source code and placed in a TextBox descendant (see license).

    This supports multiline TextBox and also RTL text.

    public class PlaceHolderTextBox : TextBox
    {
        private const int WM_KILLFOCUS = 0x0008;
        private const int WM_PAINT = 0x000F;
    
        private string _placeholderText;
    
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
    
            if (this.ShouldRenderPlaceHolderText(m))
            {
                using Graphics g = this.CreateGraphics();
                this.DrawPlaceholderText(g);
            }
        }
    
        #region PlaceHolder
    
        /// <summary>
        ///  Gets or sets the text that is displayed when the control has no text and does not have the focus.
        /// </summary>
        /// <value>The text that is displayed when the control has no text and does not have the focus.</value>
        [Localizable(true), DefaultValue("")]
        public virtual string PlaceholderText
        {
            get => _placeholderText;
            set
            {
                if (value == null)
                {
                    value = string.Empty;
                }
    
                if (_placeholderText != value)
                {
                    _placeholderText = value;
                    if (this.IsHandleCreated)
                    {
                        this.Invalidate();
                    }
                }
            }
        }
    
        //-------------------------------------------------------------------------------------------------
    
        /// <summary>
        ///  Draws the <see cref="PlaceholderText"/> in the client area of the <see cref="TextBox"/> using the default font and color.
        /// </summary>
        private void DrawPlaceholderText(Graphics graphics)
        {
            TextFormatFlags flags = TextFormatFlags.NoPadding | TextFormatFlags.Top |
                                    TextFormatFlags.EndEllipsis;
            Rectangle rectangle = this.ClientRectangle;
    
            if (this.RightToLeft == RightToLeft.Yes)
            {
                flags |= TextFormatFlags.RightToLeft;
                switch (this.TextAlign)
                {
                    case HorizontalAlignment.Center:
                        flags |= TextFormatFlags.HorizontalCenter;
                        rectangle.Offset(0, 1);
                        break;
                    case HorizontalAlignment.Left:
                        flags |= TextFormatFlags.Right;
                        rectangle.Offset(1, 1);
                        break;
                    case HorizontalAlignment.Right:
                        flags |= TextFormatFlags.Left;
                        rectangle.Offset(0, 1);
                        break;
                }
            }
            else
            {
                flags &= ~TextFormatFlags.RightToLeft;
                switch (this.TextAlign)
                {
                    case HorizontalAlignment.Center:
                        flags |= TextFormatFlags.HorizontalCenter;
                        rectangle.Offset(0, 1);
                        break;
                    case HorizontalAlignment.Left:
                        flags |= TextFormatFlags.Left;
                        rectangle.Offset(1, 1);
                        break;
                    case HorizontalAlignment.Right:
                        flags |= TextFormatFlags.Right;
                        rectangle.Offset(0, 1);
                        break;
                }
            }
    
            TextRenderer.DrawText(graphics, this.PlaceholderText, this.Font, rectangle, SystemColors.GrayText, this.BackColor, flags);
        }
        
        private bool ShouldRenderPlaceHolderText(in Message m) =>
            !string.IsNullOrEmpty(this.PlaceholderText) &&
            (m.Msg == WM_PAINT || m.Msg == WM_KILLFOCUS) &&
            !this.GetStyle(ControlStyles.UserPaint) &&
            !this.Focused && this.TextLength == 0;
    
        #endregion
    }
    
    0 讨论(0)
提交回复
热议问题