如何编程将Windows Forms所有控件设为不可选中且可正常添加到窗体
解决方案
错误原因说明
- 类型转换错误:自定义的
NSControl和原生Button都是Control的平路子类,二者没有继承关系,无法互相转换 - 泛型实例化错误:要在泛型方法中用
new T()创建实例,必须给泛型参数添加new()约束,要求对应类型存在无参构造函数
方案1:泛型工厂方法(无需单独为每个控件写子类)
直接通过泛型方法创建任意控件类型的不可选中实例,代码如下:
// 引入反射命名空间 using System.Reflection; public static class ControlFactory { // 泛型约束:T必须继承Control,且有无参构造函数 public static T CreateNonSelectableControl<T>() where T : Control, new() { T control = new T(); // SetStyle是Control的protected方法,通过反射调用 MethodInfo setStyleMethod = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic); setStyleMethod.Invoke(control, new object[] { ControlStyles.Selectable, false }); return control; } }
使用示例
// 创建不可选中的Button Button nsButton = ControlFactory.CreateNonSelectableControl<Button>(); // 创建不可选中的TextBox TextBox nsTextBox = ControlFactory.CreateNonSelectableControl<TextBox>(); // 直接添加到窗体控件集合,无需额外转换 this.Controls.Add(nsButton); this.Controls.Add(nsTextBox);
方案2:扩展方法(适配已创建的控件)
如果控件是已经实例化完成、或者通过设计器拖放生成的,可以写扩展方法批量设置:
using System.Reflection; public static class ControlExtensions { public static void SetNonSelectable(this Control control) { MethodInfo setStyleMethod = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic); setStyleMethod.Invoke(control, new object[] { ControlStyles.Selectable, false }); } // 批量设置所有子控件的扩展方法 public static void SetAllChildNonSelectable(this Control parent) { foreach (Control child in parent.Controls) { child.SetNonSelectable(); // 递归设置嵌套的子控件 if (child.HasChildren) { child.SetAllChildNonSelectable(); } } } }
使用示例
// 给单个已有的控件设置 button1.SetNonSelectable(); // 直接给整个窗体所有子控件批量设置,不用逐个处理 this.SetAllChildNonSelectable();
两种方案得到的控件都是原生控件类型,完全兼容Controls.Add方法,不需要额外转换。
内容的提问来源于stack exchange,提问作者DharMahn
相关产品推荐
相关产品推荐

