Windows 窗体通用继承

Posted

技术标签:

【中文标题】Windows 窗体通用继承【英文标题】:Windows Forms Generic Inheritance 【发布时间】:2016-01-11 19:08:20 【问题描述】:

我有这些课程:

class Foo<T1, T2> : Form 
    where T1, T2 : EventArgs

class MiddleGoo : Foo<X,Y>

class Goo : MiddleGoo

X,Y 只是从 EventArgs 派生的简单类。

我在设计器中看到了 Goo,但我想在 Foo 和 Goo 之间创建一个 Boo 类,如下所示:

class Boo<T1, Y> : Foo<T1, Y>
where T1 : EventArgs

class MiddleGoo : Boo<X,Y>

class Goo : MiddleGoo

中产阶级的解决方法不起作用,有什么想法吗?

编辑:我的意思是 Y 和 X 是像 YEventArgs 和 XEventArgs 这样的类,我的问题是当我将 Y 定义为 T2 时在设计器类 Boo 中看到,但仍然希望通过 T1 保持它的通用性。

EDIT2:我刚刚意识到我拼错了关于 Y 类的一些内容...

public class Foo<T1, T2> : Form
    where T1 : EventArgs
    where T2 : EventArgs



public class Boo<T1> : Foo<T1, MyEventArgs2>
    where T1 : EventArgs



public class MiddleGoo : Boo<MyEventArgs1>



class Goo : MiddleGoo



public class MyEventArgs2 : EventArgs



public class MyEventArgs1 : EventArgs
      

需要明确的是,我只是在 Designer 中看不到 Boo...(我也看不到 MiddleGoo,但我不需要)

【问题讨论】:

“不起作用” - 为什么?什么错误? 假设Foo的声明没有改变,第二段代码肯定是无效的,因为Y不是继承自EventArgs。那是你的“中间”课程吗?这看起来像一个 X-Y 问题。你想做什么? Winforms 设计者不喜欢 forms,更不用说继承具有通用参数的表单了。 @stuartd 使用带有通用参数的表单有很多好处,但不幸的是设计师不支持它们,我在一个非常大的项目中使用带有通用参数的表单使用我描述的技巧here 和我有设计师支持,希望你看看并发现它有帮助:) 设计者需要创建一个基类的实例来完成它的工作,最明显的方面是所见即所得的外观。当基类是泛型时,这当然是不可能的,它不可能猜测选择哪个特定类型的参数。你可以让这个类在代码中工作,但你必须不使用点击视图。 class Boo&lt;T1, Y&gt; : Foo&lt;T1, Y&gt; where T1 : EventArgs也只有加上Y:EventArgs才有效,这里Y是一个通用参数名,不是你说的Y继承自EventArgs 【参考方案1】:

对于 Visual Studio 版本 >= VS2015.1

VS2015.1 开始,Windows 窗体设计器显示具有通用基类的类,没有任何问题。因此,较新版本的 VS 不再需要其他帖子中的解决方法,并且以下类将毫无问题地显示在设计器中。

所以有一个像这样的基本泛型类:

public class BaseForm<TModel,TService> : Form

    public TModel Model get;set;
    public TService Service get; set;

您可以在设计器中毫无问题地创建派生表单:

public class FooForm: BaseForm<Foo,FooService> 


Visual Studio 的旧版本

在旧版本的 Visual Studio 中,当设计器想要在设计器中托管您的表单时,它会尝试创建表单基类的实例,并且您的类必须具有非泛型基类,以便设计器可以显示它。

所以你可以看到BaseForm&lt;T&gt;:Form 可以在设计器中显示,但CategoryForm:BaseForm&lt;Category&gt; 不能在设计器中显示。作为这些情况下的解决方法,您应该创建一个BaseCategoryForm:BaseForm&lt;Category&gt;,然后CategoryForm:BaseCategoryForm 将显示在设计器中。

例子

假设这是您接受 TModel 作为 Model 和 TService 作为 Service 的基类,例如:

public class BaseForm<TModel,TService> : Form

    public TModel Model get;set;
    public TService Service get; set;

然后以这种方式创建一个中间表单,使用这行代码:

Public Class BaseFooForm: BaseForm<Foo, FooService> 

最后的形式是这样的:

public class FooForm: BaseFooForm


现在最终的FooForm 有了设计师,您可以正常使用它。这样您就可以创建设计器支持的类。

注意

此更新也适用于控件设计器。因此,在generic base class for WinForm UserControl 中,您不再需要 VS>=VS2015.1 的这种解决方法。

【讨论】:

"BaseForm: 表单可以在设计器中显示" 并非没有进入 Designer.cs 文件并将通用参数添加到 Ctor,如下所示:部分类 BaseForm @BillW Surly 在所有情况下,构造函数都应与您的类定义匹配。 如果您的继承链是 'regular class -> generic class -> form/usercontrol',它可以正常工作。但是对于 2+ 级别的泛型,它仍然会中断。【参考方案2】:

Foo 类中的T2 类型参数需要可转换为EventArgs。但是,当您定义 Boo 类时,您并没有包含该约束。将您的 Boo 类更改为:

class Boo<T1, Y> : Foo<T1, Y>
    where T1 : EventArgs
    where Y : EventArgs

另外,您在 Foo 类声明中遇到语法错误。将其更改为:

class Foo<T1, T2>
    where T1 : EventArgs
    where T2 : EventArgs

【讨论】:

以上是关于Windows 窗体通用继承的主要内容,如果未能解决你的问题,请参考以下文章

在窗体中迭代所有控件及其相关控件的通用递归方法

使用 Visual Studio 2010 继承 Windows 窗体类

C# 转换继承的通用接口

初识windows程序

初识Windows程序

初识Windows程序