c# 如何自定义一个 control

继承 Control 类是 WinForms 自定义控件最直接方式,需禁用默认背景擦除、启用双缓冲与焦点支持,并提供无参构造函数及设计器特性以确保可用性。

c# 如何自定义一个 control

继承 Control 类是最直接的方式

自定义控件本质是扩展 System.Windows.Forms.Control(WinForms)或 System.Windows.Controls.Control(WPF),前者更轻量、适合底层绘制与事件控制。不建议从 UserControl 开始——它自带容器逻辑和设计器依赖,反而限制对绘制、消息循环、焦点行为的精细控制。

  • 若需完全掌控绘制(比如画波形图、仪表盘),继承 Control 并重写 OnPaint
  • 若要支持双缓冲防闪烁,设 this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true)
  • 必须手动调用 base.OnCreateControl()base.OnHandleCreated(),否则生命周期钩子可能失效
  • 别忘了在构造函数里设 ResizeRedraw = true,否则窗口缩放时不会自动重绘

重写 OnPaint 时绕开 GDI+ 默认背景擦除

默认 Control 在每次 OnPaint 前会用 BackColor 填充整个客户区,这会导致自绘内容被覆盖或出现残影。尤其在动画或高频刷新场景下特别明显。

  • 在构造函数中关闭默认擦除:this.SetStyle(ControlStyles.Opaque, true)
  • 同时禁用背景绘制:this.SetStyle(ControlStyles.ResizeRedraw, true)
  • 重写 OnPaintBackground 为空实现,避免父类填充背景
  • OnPaint 中只用传入的 Graphics 绘制内容,不要调用 e.Graphics.Clear(...)
protected override void OnPaint(PaintEventArgs e) {
    // 不调用 base.OnPaint(e)
    using (var pen = new Pen(Color.Blue, 2)) {
        e.Graphics.DrawLine(pen, 10, 10, 100, 100);
    }
}

响应鼠标/键盘事件必须显式启用焦点支持

直接继承 Control 的控件默认不可聚焦,KeyDownKeyPress 等事件根本不会触发,哪怕你重写了 OnKeyDown

Koobi Pro

Koobi Pro

主要功能: 无限级分类,商品可在各类别间自由转移; 组合商品概念,可以用于组配商品销售(比如服装鞋帽的颜色、尺码大小等),组合销售等销售方式; 商品的自定义属性功能,商品类别扩展属性,满足商品多属性需求(比如某一笔记本电脑,可以有cpu、内存、显示屏、硬盘等等扩展属性); 按照商品类别查看热卖、特价,允许按每个类别增加当前类别的热卖、特价等商品; 会员分级功能,会员积分功能。可根据会

下载

  • 构造函数中调用 this.TabStop = truethis.TabIndex = 0
  • 重写 CanSelect 属性返回 true
  • OnMouseDown 中主动调用 this.Focus(),否则点击不会获得输入焦点
  • 若需捕获非客户端区域(如边框)的鼠标,需处理 WM_NCHITTEST 消息,通过 WndProc 拦截

设计器支持需要 [ToolboxItem] 和默认构造函数

没有无参构造函数或缺少特性标记,控件拖不到 WinForms 设计器里,且属性面板不显示自定义属性。

  • 必须提供 public 无参构造函数:public MyCustomControl() { InitializeComponent(); }
  • 添加 [ToolboxItem(true)] 特性,否则设计器忽略该类型
  • 让属性可序列化:对希望在设计器中编辑的属性加 [Browsable(true)][DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
  • 若属性影响外观(如 LineColor),重写 OnPropertyChanged 并调用 Invalidate() 触发重绘

WinForms 自定义控件最难缠的不是绘制,而是消息分发边界——比如鼠标进入区域后移出但未触发 MouseLeave,或键盘焦点在嵌套控件间跳转时丢失。这些往往要靠精确拦截 WndProc 和检查 NativeWindow.AssignHandle 状态来定位。

https://www.php.cn/faq/2034684.html

发表回复

Your email address will not be published. Required fields are marked *