Files
2026-08-04 18:36:40 +08:00

307 lines
9.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using JinYuan.ControlLib.UCHelper;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace JinYuan.ControlLib
{
public partial class ControlBase : UserControl
{
/// <summary>
/// The is radius
/// </summary>
private bool _isRadius = false;
/// <summary>
/// The corner radius
/// </summary>
private int _cornerRadius = 24;
/// <summary>
/// The is show rect
/// </summary>
private bool _isShowRect = false;
/// <summary>
/// The rect color
/// </summary>
private Color _rectColor = Color.FromArgb(220, 220, 220);
/// <summary>
/// The rect width
/// </summary>
private int _rectWidth = 1;
/// <summary>
/// The fill color
/// </summary>
private Color _fillColor = Color.Transparent;
// 缓存绘图对象,避免重复创建(线程安全:UI线程单例)
private SolidBrush _fillBrush;
private Pen _rectPen;
private bool _isRegionDirty = true; // 标记区域是否需要重新计算
#region 公共属性(替换Refresh为Invalidate)
[Description("是否圆角"), Category("自定义")]
public virtual bool IsRadius
{
get => _isRadius;
set
{
if (_isRadius == value) return;
_isRadius = value;
_isRegionDirty = true;
Invalidate();
}
}
/// <summary>
/// 圆角角度
/// </summary>
/// <value>The coner radius.</value>
[Description("圆角角度"), Category("自定义")]
public virtual int ConerRadius
{
get => _cornerRadius;
set
{
value = Math.Max(value, 1);
if (_cornerRadius == value) return;
_cornerRadius = value;
_isRegionDirty = true;
Invalidate();
}
}
/// <summary>
/// 是否显示边框
/// </summary>
/// <value><c>true</c> if this instance is show rect; otherwise, <c>false</c>.</value>
[Description("是否显示边框"), Category("自定义")]
public virtual bool IsShowRect
{
get => _isShowRect;
set
{
if (_isShowRect == value) return;
_isShowRect = value;
Invalidate();
}
}
/// <summary>
/// 边框颜色
/// </summary>
/// <value>The color of the rect.</value>
[Description("边框颜色"), Category("自定义")]
public virtual Color RectColor
{
get => _rectColor;
set
{
if (_rectColor == value) return;
_rectColor = value;
// 重置画笔,下次使用时创建
_rectPen?.Dispose();
_rectPen = null;
Invalidate();
}
}
/// <summary>
/// 边框宽度
/// </summary>
/// <value>The width of the rect.</value>
[Description("边框宽度"), Category("自定义")]
public virtual int RectWidth
{
get => _rectWidth;
set
{
if (_rectWidth == value) return;
_rectWidth = value;
// 重置画笔,下次使用时创建
_rectPen?.Dispose();
_rectPen = null;
Invalidate();
}
}
/// <summary>
/// 当使用边框时填充颜色,当值为背景色或透明色或空值则不填充
/// </summary>
/// <value>The color of the fill.</value>
[Description("当使用边框时填充颜色,当值为背景色或透明色或空值则不填充"), Category("自定义")]
public virtual Color FillColor
{
get => _fillColor;
set
{
if (_fillColor == value) return;
_fillColor = value;
// 重置画刷,下次使用时创建
_fillBrush?.Dispose();
_fillBrush = null;
Invalidate();
}
}
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="UCControlBase" /> class.
/// </summary>
public ControlBase()
{
InitializeComponent();
// 优化双缓冲设置
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.Selectable |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles(); // 应用样式设置
}
#region 核心优化:重写OnPaint
protected override void OnPaint(PaintEventArgs e)
{
if (!Visible) return;
// 1. 仅在区域脏时更新Region
if (_isRegionDirty)
{
UpdateWindowRegion();
_isRegionDirty = false;
}
// 2. 优化绘图质量
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.Clear(BackColor); // 统一背景清除,避免闪烁
// 3. 绘制逻辑:仅在需要时创建GraphicsPath
if (_isShowRect || (_fillColor != Color.Empty && _fillColor != Color.Transparent && _fillColor != BackColor))
{
using (var graphicsPath = CreateRoundedRectPath(ClientRectangle))
{
// 绘制填充
if (_fillColor != Color.Empty && _fillColor != Color.Transparent && _fillColor != BackColor)
{
if (_fillBrush == null)
{
_fillBrush = new SolidBrush(_fillColor);
}
e.Graphics.FillPath(_fillBrush, graphicsPath);
}
// 绘制边框
if (_isShowRect)
{
if (_rectPen == null)
{
_rectPen = new Pen(_rectColor, Math.Max(1, _rectWidth)); // 避免宽度为0
}
e.Graphics.DrawPath(_rectPen, graphicsPath);
}
}
}
base.OnPaint(e);
}
#endregion
#region 辅助方法(优化逻辑+释放资源)
/// <summary>
/// 仅在区域脏时更新WindowRegion
/// </summary>
private void UpdateWindowRegion()
{
if (_isRadius)
{
using (var path = CreateRoundedRectPath(new Rectangle(-1, -1, Width + 1, Height)))
{
Region = new Region(path);
}
}
else
{
// 恢复矩形区域
using (var path = new GraphicsPath())
{
path.AddRectangle(ClientRectangle);
Region = new Region(path);
}
}
}
/// <summary>
/// 创建圆角路径
/// </summary>
/// <param name="rect">绘制矩形</param>
/// <returns>GraphicsPath</returns>
private GraphicsPath CreateRoundedRectPath(Rectangle rect)
{
var path = new GraphicsPath();
if (_isRadius && _cornerRadius > 0)
{
// 优化圆角计算:避免偏移错误
int radius = Math.Min(_cornerRadius, Math.Min(rect.Width, rect.Height) / 2);
path.AddArc(rect.X, rect.Y, radius, radius, 180f, 90f);
path.AddArc(rect.Right - radius, rect.Y, radius, radius, 270f, 90f);
path.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0f, 90f);
path.AddArc(rect.X, rect.Bottom - radius, radius, radius, 90f, 90f);
path.CloseFigure();
}
else
{
path.AddRectangle(rect);
}
return path;
}
/// <summary>
/// 释放非托管资源
/// </summary>
/// <param name="disposing">是否手动释放</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
// 释放绘图对象
_fillBrush?.Dispose();
_rectPen?.Dispose();
components?.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// 控件大小变化时标记区域脏
/// </summary>
/// <param name="e">尺寸参数</param>
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
_isRegionDirty = true;
Invalidate();
}
#endregion
/// <summary>
/// 屏蔽不必要的消息
/// </summary>
/// <param name="m">Windows消息</param>
protected override void WndProc(ref Message m)
{
if (m.Msg != 20)
{
base.WndProc(ref m);
}
}
}
}