基于TextBox的水印控件开发:水印仅初始化显示及继承类修改问题
解决继承TextBox的自定义水印控件问题
我来帮你搞定这两个核心问题:让控件正确继承TextBox,以及实现稳定显示的水印功能。
一、修改控件基类为TextBox
你新建的UserControl默认继承自UserControl,要改成继承TextBox的话,按下面步骤操作:
- 打开你的
UTextBoxWatermark.cs代码文件,找到类定义那一行,把: UserControl替换成: TextBox:public partial class UTextBoxWatermark : TextBox - 处理设计器文件:打开
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
相关产品推荐
相关产品推荐

