You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于TextBox的水印控件开发:水印仅初始化显示及继承类修改问题

解决继承TextBox的自定义水印控件问题

我来帮你搞定这两个核心问题:让控件正确继承TextBox,以及实现稳定显示的水印功能。

一、修改控件基类为TextBox

你新建的UserControl默认继承自UserControl,要改成继承TextBox的话,按下面步骤操作:

  1. 打开你的UTextBoxWatermark.cs代码文件,找到类定义那一行,把: UserControl替换成: TextBox:
    public partial class UTextBoxWatermark : TextBox
    
  2. 处理设计器文件:打开UTextBoxWatermark.Designer.cs,把所有UserControl相关的引用改成TextBox,删掉UserControl特有的代码(比如this.Controls.Add(...)这类子控件添加逻辑,因为TextBox本身是单一控件不需要子控件)。
    • 嫌麻烦的话,也可以直接在项目里新建一个类文件(右键项目→添加→类),命名为UTextBoxWatermark,让它直接继承TextBox,这样就不用处理原UserControl的冗余设计器代码了。

二、正确实现水印功能(解决只显示一次的问题)

用ControlStyles.UserPaint会干扰TextBox本身的绘制逻辑,导致光标不显示、文本绘制错乱等问题,你遇到的只显示一次是因为没有在状态变化时触发重绘。推荐用拦截Windows消息的方式实现,既稳定又不破坏TextBox原有功能:

完整代码示例

using System.Drawing;
using System.Windows.Forms;

namespace TBW1
{
    public class UTextBoxWatermark : TextBox
    {
        private string _watermarkText = "请输入内容";
        private Color _watermarkColor = Color.Gray;

        [Category("Appearance")]
        [Description("无文本时显示的提示文本")]
        public string WatermarkText
        {
            get => _watermarkText;
            set
            {
                _watermarkText = value;
                Invalidate(); // 属性变更时触发重绘
            }
        }

        [Category("Appearance")]
        [Description("水印文本的颜色")]
        public Color WatermarkColor
        {
            get => _watermarkColor;
            set
            {
                _watermarkColor = value;
                Invalidate();
            }
        }

        protected override void WndProc(ref Message m)
        {
            const int WM_PAINT = 0x000F;
            // 先让TextBox完成自身的绘制逻辑
            base.WndProc(ref m);

            // 只有当文本为空且控件未获得焦点时,才绘制水印
            if (m.Msg == WM_PAINT && string.IsNullOrEmpty(Text) && !Focused)
            {
                using (Graphics g = CreateGraphics())
                using (SolidBrush brush = new SolidBrush(WatermarkColor))
                {
                    // 让水印对齐方式和TextBox的文本对齐保持一致
                    StringFormat format = new StringFormat();
                    switch (TextAlign)
                    {
                        case HorizontalAlignment.Left:
                            format.Alignment = StringAlignment.Near;
                            break;
                        case HorizontalAlignment.Center:
                            format.Alignment = StringAlignment.Center;
                            break;
                        case HorizontalAlignment.Right:
                            format.Alignment = StringAlignment.Far;
                            break;
                    }

                    // 计算绘制区域,避开TextBox的内边距,避免水印和边框重叠
                    Padding padding = Padding;
                    Rectangle drawRect = new Rectangle(
                        padding.Left,
                        padding.Top,
                        ClientSize.Width - padding.Left - padding.Right,
                        ClientSize.Height - padding.Top - padding.Bottom);

                    // 绘制水印文本
                    g.DrawString(WatermarkText, Font, brush, drawRect, format);
                }
            }
        }

        // 焦点变化时触发重绘,显示/隐藏水印
        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);
            Invalidate();
        }

        protected override void OnLeave(EventArgs e)
        {
            base.OnLeave(e);
            Invalidate();
        }

        // 文本变化时触发重绘,显示/隐藏水印
        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            Invalidate();
        }
    }
}

这个方案的优势

  • 完全保留TextBox原有功能:光标、选中文本、快捷键等都不受影响;
  • 水印绘制时机合理:在TextBox自身绘制完成后叠加水印,不会干扰原有内容;
  • 实时更新:文本变化、焦点切换、水印属性修改时都会触发重绘,保证水印状态正确。

最后一步:编译测试

编译你的控件库项目,然后在Windows Forms应用程序里引用这个控件,拖到窗体上就能看到效果——空文本且失去焦点时显示水印,输入文本或获得焦点时水印自动隐藏。

内容的提问来源于stack exchange,提问作者user1889116

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:41:54