WinForm继承自定义UserControl中间类后VS设计器无法打开问题
WinForm UserControl继承自定义中间类后设计器无法打开的解决方案
问题场景
- 项目内多个UserControl存在约80%重复代码,因.NET不支持类多继承,通过搭建继承链实现代码复用:创建继承自
UserControl的中间类MyMiddleClass存放所有子控件共用方法,原MyForm1、MyForm2改为继承自MyMiddleClass,所有类分别存放在独立文件中 - 项目可正常编译运行,继承自
Form的主窗口Mainwindow可正常调用加载各个UserControl,但MyForm1、MyForm2的Visual Studio设计器无法打开,报错提示:
Visual Studio cannot open a designer for the file because the class within it does not inherit from a class that can be visually designed
- 已尝试为中间类添加无参构造函数、在窗体文件顶部定义第三层父类等方案,问题未解决
初始代码结构
namespace i2SIMDCProduction { public partial class MyForm1 : UserControl { public MyForm1(MyOwnClass myClass) { InitializeComponent(); this.myClass = myClass; } } } namespace i2SIMDCProduction { public partial class MyForm2 : UserControl { public MyForm2(MyOwnClass myClass) { InitializeComponent(); this.myClass = myClass; } } }
调整继承后的代码结构
namespace i2SIMDCProduction { public partial class MyForm1 : MyMiddleClass { public MyForm1(MyOwnClass myClass) { InitializeComponent(); this.myClass = myClass; } } } namespace i2SIMDCProduction { public partial class MyForm2 : MyMiddleClass { public MyForm2(MyOwnClass myClass) { InitializeComponent(); this.myClass = myClass; } } } namespace i2SIMDCProduction { public partial class MyMiddleClass : UserControl { public void MethodForAllChild() { } } }
报错根因
Visual Studio WinForm设计器加载可视化类时,要求整个继承链满足以下条件,此前的修改未覆盖全部要求:
- 所有继承链上的基类不能是抽象类,且必须显式提供无参构造函数,供设计器反射实例化
- 自定义中间基类需要添加对应设计器识别特性,告知设计器该类支持可视化设计,否则设计器会判定其为不可设计的普通类
- 自定义中间基类如果是手动新建普通CS文件实现、没有配套的设计器分部类文件,设计器无法正确识别其可设计属性
修复步骤
- 第一步:重构中间类
MyMiddleClass
不要手动新建普通类文件写MyMiddleClass,删除原有手动创建的MyMiddleClass,右键项目->添加->用户控件(Windows窗体),命名为MyMiddleClass,自动生成配套的设计器文件,再修改代码如下:using System.ComponentModel; using System.Windows.Forms; namespace i2SIMDCProduction { // 添加特性标记,明确告知设计器当前类属于可可视化设计的UserControl类型 [DesignerCategory("UserControl")] public partial class MyMiddleClass : UserControl { // 保留自动生成的无参构造,不要删除 public MyMiddleClass() { InitializeComponent(); } // 新增带参构造,满足业务传参需求,构造函数链式调用无参构造保证初始化逻辑执行 public MyMiddleClass(MyOwnClass myClass) : this() { this.myClass = myClass; } // 把所有子类共用的字段、方法、属性统一提到基类 protected MyOwnClass myClass; public void MethodForAllChild() { // 共用业务逻辑实现 } } } - 第二步:修正子类
MyForm1、MyForm2的构造函数
两个子类都需要补全设计器依赖的无参构造,带参构造改为调用基类的带参构造,避免重复赋值,以MyForm1为例:namespace i2SIMDCProduction { public partial class MyForm1 : MyMiddleClass { // 设计器实例化必须的无参构造,不可缺失 public MyForm1() { InitializeComponent(); } public MyForm1(MyOwnClass myClass) : base(myClass) { InitializeComponent(); } } }MyForm2按照完全相同的逻辑修改即可。 - 第三步:生效操作
关闭所有已打开的设计器标签页,右键解决方案选择「清理解决方案」,完成后重新生成整个项目,再双击打开MyForm1或MyForm2,设计器即可正常加载。
注意事项:如果中间类不需要添加共用UI控件,不要删除自动生成的
MyMiddleClass.Designer.cs文件,也不要修改InitializeComponent方法的访问修饰符,保持分部类结构完整即可保证设计器识别稳定性。
内容的提问来源于stack exchange,提问作者Mathieu Gauquelin
相关产品推荐
相关产品推荐

