WinForms C#使用clsResize类实现控件随窗体自动缩放时报错如何解决?
问题原因
你遇到的索引越界错误由以下几个常见原因导致:
- 构造函数中订阅了
Resize事件,该事件会在窗体Load事件执行前就触发,此时还未调用_get_initial_size方法存储控件初始尺寸,_arr_control_storage为空列表,访问索引时直接报错 - 窗体最小化时
ClientSize宽高为0,计算缩放比例时会出现无效值,后续设置控件尺寸时触发异常 - 极端场景下两次递归获取控件的顺序或数量不一致,导致索引不匹配
修复方案
只需要修改clsResize类即可,不需要修改窗体侧的调用代码:
- 在
_resize方法入口添加边界校验,避免未初始化、窗体最小化时执行缩放逻辑 - 索引访问前添加长度校验,避免越界
- 优化递归获取控件的逻辑,保证两次返回的控件顺序一致
完整修改后的
clsResize代码 using System; using System.Collections.Generic; using System.Linq; using System.Drawing; using System.Windows.Forms; public class clsResize { List<Rectangle> _arr_control_storage = new List<Rectangle>(); private bool showRowHeader = false; public clsResize(Form _form_) { form = _form_; _formSize = _form_.ClientSize; _fontsize = _form_.Font.Size; } private float _fontsize { get; set; } private SizeF _formSize {get;set; } private Form form { get; set; } public void _get_initial_size() { _arr_control_storage.Clear(); // 每次调用先清空旧数据 var _controls = _get_all_controls(form).OrderBy(c=>c.Name).ToList(); // 按名称排序保证顺序固定 foreach (Control control in _controls) { _arr_control_storage.Add(control.Bounds); if (control is DataGridView dgv) _dgv_Column_Adjust(dgv, showRowHeader); } } public void _resize() { // 边界校验:未初始化、窗体最小化、初始尺寸无效时直接返回 if (_arr_control_storage.Count == 0 || form.WindowState == FormWindowState.Minimized || _formSize.Width <=0 || _formSize.Height <=0) { return; } double _form_ratio_width = (double)form.ClientSize.Width / (double)_formSize.Width; double _form_ratio_height = (double)form.ClientSize.Height / (double)_formSize.Height; var _controls = _get_all_controls(form).OrderBy(c=>c.Name).ToList(); // 同样按名称排序 for(int _pos=0; _pos < _controls.Count && _pos < _arr_control_storage.Count; _pos++) // 用for循环替代,直接加长度校验 { Control control = _controls[_pos]; Size _controlSize = new Size( (int)(_arr_control_storage[_pos].Width * _form_ratio_width), (int)(_arr_control_storage[_pos].Height * _form_ratio_height)); Point _controlposition = new Point( (int)(_arr_control_storage[_pos].X * _form_ratio_width), (int)(_arr_control_storage[_pos].Y * _form_ratio_height)); control.Bounds = new Rectangle(_controlposition, _controlSize); if (control is DataGridView dgv) _dgv_Column_Adjust(dgv, showRowHeader); // 字体大小计算增加最小最大值限制,避免字体过大或过小 float newFontSize = (float)((_fontsize * _form_ratio_width + _fontsize * _form_ratio_height) / 2); newFontSize = Math.Max(6, Math.Min(72, newFontSize)); control.Font = new Font(form.Font.FontFamily, newFontSize); } } private void _dgv_Column_Adjust(DataGridView dgv, bool _showRowHeader) { int intRowHeader = 0; const int Hscrollbarwidth = 5; if (_showRowHeader) intRowHeader = dgv.RowHeadersWidth; else dgv.RowHeadersVisible = false; if (dgv.ColumnCount == 0 || dgv.Width <= intRowHeader + Hscrollbarwidth) return; // 列数为0或者宽度过小时直接返回 for (int i = 0; i < dgv.ColumnCount; i++) { if (dgv.Dock == DockStyle.Fill) dgv.Columns[i].Width = ((dgv.Width - intRowHeader) / dgv.ColumnCount); else dgv.Columns[i].Width = ((dgv.Width - intRowHeader - Hscrollbarwidth) / dgv.ColumnCount); } } private static IEnumerable<Control> _get_all_controls(Control c) { return c.Controls.Cast<Control>() .SelectMany(item => _get_all_controls(item)) .Concat(c.Controls.Cast<Control>()) .Where(control => !string.IsNullOrEmpty(control.Name)); } }
可选优化(非必须)
如果有动态添加/删除控件的需求,在修改控件集合后重新调用一次_form_resize._get_initial_size()即可。
内容的提问来源于stack exchange,提问作者Bumba
相关产品推荐
相关产品推荐

