307 lines
9.7 KiB
C#
307 lines
9.7 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|
||
}
|