我从事一个问题,在Windows窗体继承控件和需要它的一些建议。
我使用用于在列表项的基类(由面板的自制GUI列表)和某些遗传控制是用于数据的每种类型的可添加到列表中。
有与它没有问题,但我现在发现,这将是正确的,使基本控制一个抽象类,因为它有方法,需要在所有继承的控制来实现,从里面的代码调用基控制,但决不能并不能在基类来实现。
当我标志着基控制,抽象,在Visual Studio 2008设计拒绝加载窗口。
是否有一种方式来获得有由抽象基控制的设计工作?
我从事一个问题,在Windows窗体继承控件和需要它的一些建议。
我使用用于在列表项的基类(由面板的自制GUI列表)和某些遗传控制是用于数据的每种类型的可添加到列表中。
有与它没有问题,但我现在发现,这将是正确的,使基本控制一个抽象类,因为它有方法,需要在所有继承的控制来实现,从里面的代码调用基控制,但决不能并不能在基类来实现。
当我标志着基控制,抽象,在Visual Studio 2008设计拒绝加载窗口。
是否有一种方式来获得有由抽象基控制的设计工作?
我知道必须有一个方法可以做到这一点(我找到了一个办法做到这一点干净)。 盛的解决方案是什么我想出了一个临时的解决方法,但经过朋友指出, Form
最终从继承的类abstract
类,我们应该能够完成这件事。 如果他们能做到这一点,我们可以做到这一点。
我们从这个代码就到了问题
Form1 : Form
public class Form1 : BaseForm
...
public abstract class BaseForm : Form
这是最初的问题发挥了作用。 正如前面所说的,有朋友指出, System.Windows.Forms.Form
实现了一个基类是抽象的。 我们能够找到...
继承层次结构:
public **abstract** class MarshalByRefObject
) 从这一点,我们知道这是可能的设计表明,实施了抽象基类的类,它只是不能显示出设计师类,立即实施基本抽象类。 必须有在最大5其间,但我们测试了1层抽象的,最初与此解决方案上来。
public class Form1 : MiddleClass
...
public class MiddleClass : BaseForm
...
public abstract class BaseForm : Form
...
这实际上工程和设计使得它很好,问题解决了....除非你在生产中的应用,这是因为在设计师的WinForms的不足之处只需要具有继承的一个额外的水平!
这不是一个100%万无一失的解决方案,但它的相当不错。 基本上你使用#if DEBUG
拿出精致的解决方案。
Form1.cs的
#if DEBUG
public class Form1 : MiddleClass
#else
public class Form1 : BaseForm
#endif
...
MiddleClass.cs
public class MiddleClass : BaseForm
...
BaseForm.cs
public abstract class BaseForm : Form
...
只使用在“初始解决方案”中所列的解决方案,如果是在调试模式下这样做是什么。 我们的想法是,你永远不会通过调试版本发布生产方式和你将永远在调试模式设计。
设计师将始终运行反对建在当前模式下的代码,所以你不能在释放模式使用设计。 但是,只要你在调试模式设计和发布建立在发行模式的代码,你是好去。
唯一的神火的解决办法是,如果你可以通过预处理指令测试设计模式。
@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);
}
}
最后,我们只是应用TypeDescriptionProvider属性的Abastract控制。
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<AbstractControl, UserControl>))]
public abstract class AbstractControl : UserControl
...
仅此而已。 无需中间的控制。
而供应商类可以,因为我们希望在同一个解决方案被应用到许多摘要基地。
*编辑*也需要在App.config以下
<appSettings>
<add key="EnableOptimizedDesignerReloading" value="false" />
</appSettings>
感谢@ user3057544的意见。
@Smelch,感谢有用的答案,我也陷入了同样的问题最近。
以下是您的文章,以防止编译警告(通过将中基类的微小变化#if DEBUG
预处理器指令):
public class Form1
#if DEBUG
: MiddleClass
#else
: BaseForm
#endif
我有一个类似的问题,而是找到了一种方法来重构东西的地方一个抽象基类的使用界面:
interface Base {....}
public class MyUserControl<T> : UserControl, Base
where T : /constraint/
{ ... }
这可能并不适用于所有情况,但如果可能的话,会导致较条件编译一个清晰的解决方案。
我使用的解决这个答案另一个问题,哪个环节这篇文章 。 文章建议使用自定义TypeDescriptionProvider
和具体实施的抽象类。 设计师将要求使用哪种类型的自定义的供应商,你的代码可以返回的具体类,使设计师是高兴,而你必须在抽象类是如何表现为具体的类完全控制。
更新:我包括一个文件的代码示例中我的回答另一个问题。 该代码有没有工作,但有时我不得不通过清洁/建造周期为我的答案注意到得到它的工作。
我对胡安·卡洛斯·迪亚斯解决方案小费。 这对我的作品很大,但有些问题的。 当我开始VS并进入设计者一切工作正常。 但是,运行该解决方案后,然后停止并退出它,然后再次尝试,然后再次输入设计师出现异常,直到重新启动VS. 但我发现它的解决方案 - 一切都做的是下面添加到您的app.config
<appSettings>
<add key="EnableOptimizedDesignerReloading" value="false" />
</appSettings>
由于抽象类public abstract class BaseForm: Form
给出了一个错误,并避免使用设计的,我想出了使用虚拟成员。 基本上,代替声明抽象方法,我声明具有最小体作为可能的虚拟方法。 下面是我做了什么:
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. */
由于DataForm
应该是与抽象成员的抽象类displayFields
,我“打假”这种行为与虚拟成员以避免抽象。 设计者没有再抱怨,一切工作正常,我。
这是一种解决方法更具可读性,但因为它是不是抽象的,我必须确保所有子类DataForm
有其实施的displayFields
。 因此,使用这种技术时要小心。
我已经得到了谁的人说的一些技巧TypeDescriptionProvider
由胡安·卡洛斯·迪亚斯不工作,不喜欢的条件编译既不:
首先,您可能需要重新启动Visual Studio在你的代码的形式设计工作的变化(我不得不,简单的重建没有工作-或者不是每次)。
我会提出我这个问题的解决方案抽象基表的情况。 比方说,你有一个BaseForm
的类,并且希望在此基础上的任何形式是可设计的(这将是Form1
)。 该TypeDescriptionProvider
由胡安·卡洛斯·迪亚斯表现为没有为我工作也。 这是我如何做它的工作,通过与中产阶级溶液(smelch)加入它,但没有#if DEBUG
条件编译,并与一些更正:
[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
}
}
注意在基本形式的类属性。 然后,你就必须申报TypeDescriptionProvider
和两个中产阶级 ,不过不用担心,他们是无形的和不相关的Form1的开发商 。 第一种实现抽象构件(并且使基类非摘要)。 第二个是空的 - 它只是需要对VS窗体设计工作。 然后你的第二中产阶级分配给TypeDescriptionProvider
的BaseForm
。 没有条件编译。
我有两个问题:
第一个问题(你可能没有它,因为它的东西,困扰着我在我的项目在一些地方的另一个,通常会产生“无法将类型X输入X”除外)。 我解决它在TypeDescriptionProvider
通过比较类型名称 (全名),而不是比较的类型(见下文)。
第二个问题。 我真的不知道为什么基本形式的控制并不是在Form1类设计性和它们的位置后失去了调整,但我身边的工作它(不是一个很好的解决方案 - 如果你知道任何更好的,请写)。 我只是手动移动基本形式的按钮(这应该是在右下角),以正确的位置在从基本形式的Load事件异步调用的方法: BeginInvoke(new Action(CorrectLayout));
我的基类,只有“确定”和“取消”按钮,这样的情况很简单。
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
{
}
在这里,你有稍微修改后的版本TypeDescriptionProvider
:
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);
}
}
就是这样!
你不必解释什么根据您的基本形式的形式将来开发者和他们没有做任何的技巧来设计他们的形式! 我认为这是最干净的解决方案也可以是(除了控制重新定位)。
一个提示:
如果由于某种原因,设计师仍然拒绝为你工作,你总是可以做改变的简单的一招public class Form1 : BaseForm
,以public class Form1 : BaseFormMiddle1
(或BaseFormMiddle2
)的代码文件,在VS窗体设计器进行编辑然后再改变回去。 我喜欢这一招在条件编译,因为它是不太可能忘记并释放了错误的版本 。
Windows窗体设计器是创建的基类窗体/控件的实例和应用的解析结果InitializeComponent
。 这就是为什么你可以设计由项目向导创建的形式,甚至没有建设项目。 由于这种行为,你也不能设计从抽象类派生的控件。
您可以实现这些抽象方法,并抛出时,它没有设计器中运行异常。 谁从控制派生程序员必须提供不调用基类实现的实现。 否则,程序会崩溃。
你可以只在有条件的编译abstract
关键字不插入一个单独的类:
#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
}
这个工程提供了BaseForm
没有任何抽象方法(在abstract
关键词,因此只可以防止类的运行时实例化)。