子窗体继承时未显示来自抽象基窗体的控件

Posted

技术标签:

【中文标题】子窗体继承时未显示来自抽象基窗体的控件【英文标题】:Controls from abstract base-Form not shown when inherited by a child Form 【发布时间】:2015-06-29 20:45:47 【问题描述】:

我正在关注 Juan Carlos Diaz here提供的解决方案

我的问题是我没有看到任何抽象类的表单控件显示在具体类中。我希望他们在那里,以便我可以将设计编辑器与具体类一起使用。

以下是我采取的步骤:

    创建新的解决方案 创建一个新的 winforms 项目 (.Net 4.5.2) 创建一个名为AbstractBaseForm.cs 的表单,并添加一些hello world 逻辑:

    abstract关键字添加到AbstractBaseForm.cs;您的代码应如下所示:

    public abstract partial class AbstractBaseForm : Form
    
        protected AbstractBaseForm()
        
            InitializeComponent();
        
    
        private void button1_Click(object sender, EventArgs e)
        
            label1.Text = "Hello World";
        
    
    

    将以下类添加到您的项目中:

    public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
    
        public AbstractControlDescriptionProvider()
            : base(TypeDescriptor.GetProvider(typeof (TAbstract)))
        
        
    
        public override Type GetReflectionType(Type objectType, object instance)
        
            if (objectType == typeof (TAbstract))
                return typeof (TBase);
    
            return base.GetReflectionType(objectType, instance);
        
    
        public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
        
            if (objectType == typeof (TAbstract))
                objectType = typeof (TBase);
    
            return base.CreateInstance(provider, objectType, argTypes, args);
        
    
    

    将以下属性添加到AbstractBaseForm.cs

    [TypeDescriptionProvider(typeof (AbstractControlDescriptionProvider<AbstractBaseForm, Form>))]
    public abstract partial class AbstractBaseForm : Form
    
    

    向项目添加第二个表单,标题为 ConcreteForm.cs,并让它继承自 AbstractBaseForm.cs,如下所示:

    public partial class ConcreteForm : AbstractBaseForm
    
        public ConcreteForm()
        
             InitializeComponent();
        
    
    

    更改 program.cs 以便它像这样加载 ConcreteForm.cs

    Application.Run(new ConcreteForm());
    

    执行项目。您应该看到ConcreteForm.cs 加载,单击按钮将标签更改为“Hello World”。

    关闭应用程序,然后单击ConcreteForm.cs,打开其设计视图。你会看到这个:

为什么我在设计视图中看不到从AbstractBaseForm.cs 继承的控件?

【问题讨论】:

您是否检查以确保您正在重载 InitializeComponent() 这似乎是最有可能开始的地方。 (并且您没有使用在 ConcreteForm 中生成的新版本 @Rootix 你的意思是覆盖? InitializeComponent 是 IDE 生成的部分类的私有方法。它不是虚拟的,子类无法访问。然而,当子类的默认构造函数被调用时,它将被自动调用。 Hmya,你需要停止将枪对准你的脚并扣动扳机。设计者需要能够创建基类的实例。您可以通过重定向类型来伪造它,但是当然可以,您将获得 Form 类的行为。它没有任何控件。删除 abstract 关键字,继续你的生活。 @HansPassant:我认为你超出了我的想象。假设我在基类中单击按钮时调用以下方法: public virtual string GetMessage() return "Hello World"; 然后在子类中假设我执行以下操作: public override string GetMessage() return "Goodbye World!"; -> 根据您的建议,我将无法做到这一点,实际上将无法编译。我在您的建议中遗漏了什么? 没有。你唯一可能做错的事情就是不去尝试。 【参考方案1】:

添加对基础构造函数的调用

public partial class ConcreteForm : AbstractBaseForm

    public ConcreteForm() : base()
    
         InitializeComponent();
    

正如@hans-passant 建议的那样,删除 abstract 关键字。使用 abstract 关键字,我收到以下错误:

设计者必须创建一个类型的实例 'WindowsFormsApplication1.Form1' 但它不能因为类型是 声明为抽象。

【讨论】:

谢谢汉斯和本。效果很好,我仍然可以使用虚拟/覆盖。我的错误就在我耳边:我认为我需要使用抽象类来使用虚拟/覆盖关键字。

以上是关于子窗体继承时未显示来自抽象基窗体的控件的主要内容,如果未能解决你的问题,请参考以下文章

Delphi_子窗体继承父窗体后如何显示父窗体上的控件

Delphi中子窗体如何继承父窗体

WPF 子窗体 在 父窗体 中 打开,初学不懂,请指教

关于winform子窗体刷新父窗体

delphi 子窗体如何继承主窗体的方法

C# Winform主窗体和子窗体之间如何相互操作对方的控件