Winform界面自动缩放帮助类
/// <summary>
/// 自动调整控件大小辅助类
/// 自动根据窗体或容器控件的大小变化,按比例调整所有子控件的大小、位置、字体等属性
/// </summary>
public class AutoSizeHelper : IDisposable
{
// 存储所有控件及其原始布局信息的字典
private readonly Dictionary<Control, ControlLayoutInfo> _controlLayoutInfos =
new Dictionary<Control, ControlLayoutInfo>();
private readonly Control _topControl; // 顶级控件(通常是Form)
private readonly ControlLayoutInfo _topLayoutInfo; // 顶级控件的原始布局信息
private double _widthScale = 1.0; // 宽度缩放比例
private double _heightScale = 1.0; // 高度缩放比例
/// <summary>
/// 构造函数
/// </summary>
/// <param name="control">需要自动调整大小的顶级控件(通常是窗体)</param>
/// <exception cref="ArgumentNullException">当control参数为null时抛出</exception>
public AutoSizeHelper(Control control)
{
// 参数验证
_topControl = control ?? throw new ArgumentNullException(nameof(control));
// 注册窗体大小变化事件
_topControl.Resize += Control_Resize;
// 获取顶级控件的原始布局信息
_topLayoutInfo = GetControlLayoutInfo(_topControl);
// 递归收集所有子控件的布局信息
CollectControlInfos(_topControl);
}
/// <summary>
/// 递归收集控件树中所有控件的布局信息
/// </summary>
/// <param name="control">当前控件</param>
private void CollectControlInfos(Control control)
{
if (control == null) return;
// 将当前控件及其布局信息添加到字典中
_controlLayoutInfos[control] = GetControlLayoutInfo(control);
// 递归处理所有子控件
foreach (Control subControl in control.Controls)
{
CollectControlInfos(subControl);
}
}
/// <summary>
/// 窗体大小变化事件处理函数
/// </summary>
/// <param name="sender">事件源</param>
/// <param name="e">事件参数</param>
private void Control_Resize(object sender, EventArgs e)
{
// 防止窗体大小为0或负数时计算缩放比例
if (_topControl.Size.Width <= 0 || _topControl.Size.Height <= 0)
return;
// 计算宽度和高度的缩放比例
_widthScale = _topControl.Size.Width / (double)_topLayoutInfo.Size.Width;
_heightScale = _topControl.Size.Height / (double)_topLayoutInfo.Size.Height;
// 调整所有控件
AdjustAllControls();
}
/// <summary>
/// 调整所有控件的布局
/// </summary>
private void AdjustAllControls()
{
// 遍历字典,调整每个控件
foreach (var kvp in _controlLayoutInfos)
{
AdjustControl(kvp.Key, kvp.Value);
}
}
/// <summary>
/// 调整单个控件的布局
/// </summary>
/// <param name="control">要调整的控件</param>
/// <param name="layoutInfo">控件的原始布局信息</param>
private void AdjustControl(Control control, ControlLayoutInfo layoutInfo)
{
try
{
// 跳过顶级控件自身的位置和大小调整(只调整其子控件)
if (!control.Equals(_topControl))
{
// 按比例调整控件大小
control.Width = (int)(layoutInfo.Size.Width * _widthScale);
control.Height = (int)(layoutInfo.Size.Height * _heightScale);
// 按比例调整控件位置
control.Location = new Point(
(int)(layoutInfo.Location.X * _widthScale),
(int)(layoutInfo.Location.Y * _heightScale));
}
// 调整边距(按比例)
control.Margin = new Padding(
(int)(layoutInfo.Margin.Left * _widthScale),
(int)(layoutInfo.Margin.Top * _heightScale),
(int)(layoutInfo.Margin.Right * _widthScale),
(int)(layoutInfo.Margin.Bottom * _heightScale));
// 调整内边距(按比例)
control.Padding = new Padding(
(int)(layoutInfo.Padding.Left * _widthScale),
(int)(layoutInfo.Padding.Top * _heightScale),
(int)(layoutInfo.Padding.Right * _widthScale),
(int)(layoutInfo.Padding.Bottom * _heightScale));
// 调整字体大小(使用最小比例保持字体纵横比)
// 使用最小比例防止字体在不同方向上拉伸不均匀
var scale = Math.Min(_widthScale, _heightScale);
control.Font = WithSize(layoutInfo.Font, (float)(layoutInfo.Font.Size * scale));
}
catch (Exception ex)
{
// 记录异常,而不是静默吞没
// 在实际项目中,可以使用日志框架记录异常
System.Diagnostics.Debug.WriteLine($"调整控件 {control.Name} 时出错: {ex.Message}");
// 这里可以选择重新抛出或处理特定异常,但通常不直接抛出以免影响其他控件调整
}
}
/// <summary>
/// 添加新控件到自动调整列表中
/// </summary>
/// <param name="control">要添加的控件</param>
public void AddControl(Control control)
{
if (control == null) return;
// 收集控件及其所有子控件的布局信息
CollectControlInfos(control);
}
/// <summary>
/// 从自动调整列表中移除控件
/// </summary>
/// <param name="control">要移除的控件</param>
public void RemoveControl(Control control)
{
if (control == null) return;
// 移除控件本身
_controlLayoutInfos.Remove(control);
// 递归移除所有子控件
foreach (Control subControl in control.Controls)
{
RemoveControl(subControl);
}
}
/// <summary>
/// 创建具有新字体大小的字体对象
/// </summary>
/// <param name="originalFont">原始字体</param>
/// <param name="newSize">新字体大小</param>
/// <returns>新的字体对象</returns>
/// <exception cref="ArgumentNullException">当originalFont为null时抛出</exception>
private static Font WithSize(Font originalFont, float newSize)
{
if (originalFont == null)
throw new ArgumentNullException(nameof(originalFont));
// 确保字体大小有效,设置最小字体大小
if (newSize <= 0)
newSize = 8.0f; // 最小字体大小
// 创建新字体,保持其他属性不变
return new Font(originalFont.FontFamily, newSize, originalFont.Style, originalFont.Unit);
}
/// <summary>
/// 获取控件的布局信息
/// </summary>
/// <param name="control">控件</param>
/// <returns>控件的布局信息对象</returns>
private static ControlLayoutInfo GetControlLayoutInfo(Control control)
{
return new ControlLayoutInfo
{
Size = control.Size, // 控件大小
Location = control.Location, // 控件位置
Margin = control.Margin, // 外边距
Padding = control.Padding, // 内边距
Font = control.Font?.Clone() as Font ?? control.Font // 字体(克隆以防修改)
};
}
/// <summary>
/// 控件布局信息类
/// 用于保存控件的原始布局信息,作为调整时的基准
/// </summary>
private class ControlLayoutInfo
{
public Size Size { get; set; } // 控件大小
public Point Location { get; set; } // 控件位置
public Padding Margin { get; set; } // 外边距
public Padding Padding { get; set; } // 内边距
public Font Font { get; set; } // 字体
}
#region IDisposable Support
private bool _disposed = false; // 释放标志
/// <summary>
/// 释放资源
/// </summary>
/// <param name="disposing">true表示释放托管资源,false表示仅释放非托管资源</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// 取消事件订阅,防止内存泄漏
if (_topControl != null)
{
_topControl.Resize -= Control_Resize;
}
// 释放字体资源(Font实现了IDisposable)
foreach (var layoutInfo in _controlLayoutInfos.Values)
{
layoutInfo.Font?.Dispose();
}
// 清空字典
_controlLayoutInfos.Clear();
}
_disposed = true;
}
}
/// <summary>
/// 实现IDisposable接口
/// </summary>
public void Dispose()
{
Dispose(true);
// 阻止垃圾回收器调用Finalize方法
GC.SuppressFinalize(this);
}
#endregion
#region 示例代码
//public partial class MainForm : Form
//{
// private AutoSizeHelper _autoSizeHelper;
// public MainForm()
// {
// InitializeComponent();
// // 在窗体构造函数中初始化
// _autoSizeHelper = new AutoSizeHelper(this);
// }
// // 动态添加控件时需要添加到调整列表中
// private void AddDynamicControl()
// {
// Button dynamicButton = new Button { Text = "动态按钮" };
// this.Controls.Add(dynamicButton);
// _autoSizeHelper.AddControl(dynamicButton);
// }
//}
#endregion
}

浙公网安备 33010602011771号