Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何让Visual Studio 2008 Windows窗体设计器呈现实现抽象基类的窗体?_C#_Winforms_Visual Studio 2008_Windows Forms Designer - Fatal编程技术网

C# 如何让Visual Studio 2008 Windows窗体设计器呈现实现抽象基类的窗体?

C# 如何让Visual Studio 2008 Windows窗体设计器呈现实现抽象基类的窗体?,c#,winforms,visual-studio-2008,windows-forms-designer,C#,Winforms,Visual Studio 2008,Windows Forms Designer,我遇到了Windows窗体中继承控件的问题,需要一些建议 我确实为列表中的项目(由面板组成的自制GUI列表)使用基类,并为可以添加到列表中的每种类型的数据使用一些继承控件 它没有问题,但我现在发现,使基控件成为一个抽象类是正确的,因为它有方法,需要在所有继承控件中实现,从基控件内部的代码调用,但不能也不能在基类中实现 当我将基本控件标记为抽象时,VisualStudio2008设计器拒绝加载窗口 有没有办法让设计器使用抽象的基控件?Windows窗体设计器正在创建窗体/控件基类的实例,并应用In

我遇到了Windows窗体中继承控件的问题,需要一些建议

我确实为列表中的项目(由面板组成的自制GUI列表)使用基类,并为可以添加到列表中的每种类型的数据使用一些继承控件

它没有问题,但我现在发现,使基控件成为一个抽象类是正确的,因为它有方法,需要在所有继承控件中实现,从基控件内部的代码调用,但不能也不能在基类中实现

当我将基本控件标记为抽象时,VisualStudio2008设计器拒绝加载窗口


有没有办法让设计器使用抽象的基控件?

Windows窗体设计器正在创建窗体/控件基类的实例,并应用
InitializeComponent
的解析结果。这就是为什么您可以设计由项目向导创建的表单,而无需构建项目。由于这种行为,您也无法设计从抽象类派生的控件


您可以实现这些抽象方法,并在异常未在设计器中运行时引发异常。从控件派生的程序员必须提供一个不调用基类实现的实现。否则程序就会崩溃。

我知道一定有办法做到这一点(我找到了一种干净的方法)。盛的解决方案正是我临时想出的解决方案,但在一位朋友指出
表单
类最终继承自
抽象
类之后,我们应该能够完成这项工作。如果他们能做到,我们也能做到

我们从这个代码开始解决这个问题

Form1 : Form
问题 这就是最初的问题发挥作用的地方。如前所述,一位朋友指出,
System.Windows.Forms.Form
实现了一个抽象的基类。我们能够找到

更好解决方案的证明
  • 继承层次结构:

      • 公共**抽象**类MarshallByRefObject
由此,我们知道设计器可以显示实现了基抽象类的类,而不能显示立即实现了基抽象类的设计器类。中间必须有最多5层,但我们测试了1层抽象,最初提出了这个解决方案

初始解 这实际上是可行的,设计师把它处理得很好,问题解决了。。。。除非您在生产应用程序中有一个额外的继承级别,这只是因为winforms designer中的不足才有必要

这不是一个100%可靠的解决方案,但它非常好。基本上,您可以使用
#if DEBUG
来提出优化的解决方案

精制溶液 表格1.cs

public class Form1
#if DEBUG
    : MiddleClass
#else 
    : BaseForm
#endif
...
中产阶级

public class MiddleClass : BaseForm
... 
BaseForm.cs

public abstract class BaseForm : Form
... 
如果处于调试模式,则只使用“初始解决方案”中概述的解决方案。其思想是,您永远不会通过调试构建来发布生产模式,并且您将始终在调试模式下进行设计

设计器将始终针对在当前模式下生成的代码运行,因此不能在发布模式下使用设计器。但是,只要您在调试模式下进行设计并发布在发布模式下构建的代码,就可以继续


唯一的surefire解决方案是,如果您可以通过预处理器指令测试设计模式。

@Smelch,感谢您的帮助,因为我最近遇到了相同的问题

以下是对帖子的一个小改动,以防止出现编译警告(通过将基类放入
#if DEBUG
预处理器指令中):


我也有类似的问题,但找到了一种重构方法,用接口代替抽象基类:

interface Base {....}

public class MyUserControl<T> : UserControl, Base
     where T : /constraint/
{ ... }
接口基{….}
公共类MyUserControl:UserControl,基
其中T:/constraint/
{ ... }
这可能不适用于所有情况,但如果可能,它会产生一个比条件编译更干净的解决方案。

我在另一个问题中使用该解决方案,该问题链接到。本文建议使用定制的
TypeDescriptionProvider
和抽象类的具体实现。设计器将询问自定义提供程序要使用哪些类型,并且您的代码可以返回具体类,这样当您完全控制抽象类如何显示为具体类时,设计器会感到高兴


更新:我在回答另一个问题时也提到了这个问题。那里的代码确实有效,但有时我必须经历一个清理/构建周期,正如我在回答中所指出的那样,以使其正常工作。

@smelch,有一个更好的解决方案,不必创建中间控件,即使是用于调试

我们想要什么

首先,让我们定义最终类和基本抽象类

public class MyControl : AbstractControl
...
public abstract class AbstractControl : UserControl // Also works for Form
...
现在我们只需要一个描述提供程序

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);
    }
}
公共类AbstractControlDescriptionProvider:TypeDescriptionProvider
{
公共AbstractControlDescriptionProvider()
:base(TypeDescriptor.GetProvider(typeof(TAbstract)))
{
}
公共重写类型GetReflectionType(类型objectType,对象实例)
{
if(objectType==typeof(TAbstract))
返回类型(TBase);
返回base.GetReflectionType(objectType,instance);
}
公共重写对象CreateInstance(IServiceProvider提供程序,类型objectType,类型[]argTypes,对象[]args)
{
if(objectType==typeof(TAbstract))
objectType=typeof(TBase);
返回base.CreateInstance(提供程序、对象类型、参数
interface Base {....}

public class MyUserControl<T> : UserControl, Base
     where T : /constraint/
{ ... }
public class MyControl : AbstractControl
...
public abstract class AbstractControl : UserControl // Also works for Form
...
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);
    }
}
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<AbstractControl, UserControl>))]
public abstract class AbstractControl : UserControl
...
<appSettings>
    <add key="EnableOptimizedDesignerReloading" value="false" />
</appSettings>
#if DEBUG
  // Visual Studio 2008 designer complains when a form inherits from an 
  // abstract base class
  public class BaseForm: Form {
#else
  // For production do it the *RIGHT* way.
  public abstract class BaseForm: Form {
#endif

    // Body of BaseForm goes here
  }
public class DataForm : Form {
    protected virtual void displayFields() {}
}

public partial class Form1 : DataForm {
    protected override void displayFields() { /* Do the stuff needed for Form1. */ }
    ...
}

public partial class Form2 : DataForm {
    protected override void displayFields() { /* Do the stuff needed for Form2. */ }
    ...
}

/* Do this for all classes that inherit from DataForm. */
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<BaseForm, BaseFormMiddle2>))]   // BaseFormMiddle2 explained below
public abstract class BaseForm : Form
{
    public BaseForm()
    {
        InitializeComponent();
    }

    public abstract void SomeAbstractMethod();
}


public class Form1 : BaseForm   // Form1 is the form to be designed. As you see it's clean and you do NOTHING special here (only the the normal abstract method(s) implementation!). The developer of such form(s) doesn't have to know anything about the abstract base form problem. He just writes his form as usual.
{
    public Form1()
    {
        InitializeComponent();
    }

    public override void SomeAbstractMethod()
    {
        // implementation of BaseForm's abstract method
    }
}
class BaseFormMiddle1 : BaseForm
{
    protected BaseFormMiddle1()
    {
    }

    public override void SomeAbstractMethod()
    {
        throw new NotImplementedException();  // this method will never be called in design mode anyway
    }
}


class BaseFormMiddle2 : BaseFormMiddle1  // empty class, just to make the VS designer working
{
}
public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
{
    public AbstractControlDescriptionProvider()
        : base(TypeDescriptor.GetProvider(typeof(TAbstract)))
    {
    }

    public override Type GetReflectionType(Type objectType, object instance)
    {
        if (objectType.FullName == typeof(TAbstract).FullName)  // corrected condition here (original condition was incorrectly giving false in my case sometimes)
            return typeof(TBase);

        return base.GetReflectionType(objectType, instance);
    }

    public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
    {
        if (objectType.FullName == typeof(TAbstract).FullName)  // corrected condition here (original condition was incorrectly giving false in my case sometimes)
            objectType = typeof(TBase);

        return base.CreateInstance(provider, objectType, argTypes, args);
    }
}
  <appSettings>
   <add key="EnableOptimizedDesignerReloading" value="false" />
  </appSettings>