Visual Studio设计器中的抽象UserControlinheritance
abstract class CustomControl : UserControl { protected abstract int DoStuff(); } class DetailControl : CustomControl { protected override int DoStuff() { // do stuff return result; } }
我在表单中删除了一个DetailControl。 它在运行时正确呈现,但设计器显示错误并且无法打开,因为基本用户控件是抽象的。
目前,我正在考虑以下补丁,这对我来说似乎很不对,因为我希望子类被强制实现该方法。
class CustomControl : UserControl { protected virtual int DoStuff() { throw new InvalidOperationException("This method must be overriden."); } } class DetailControl : CustomControl { protected override int DoStuff() { // do stuff return result; } }
任何人都有更好的想法如何解决这个问题?
您可以使用TypeDescriptionProviderAttribute为抽象基类提供具体的设计时实现。 有关详细信息,请参见http://wonkitect.wordpress.com/2008/06/20/using-visual-studio-whidbey-to-design-abstract-forms/ 。
我们想要什么
首先,让我们定义最终类和基本抽象类。
public class MyControl : AbstractControl ... public abstract class AbstractControl : UserControl // Also works for Form ...
现在我们所需要的只是一个描述提供者 。
public class AbstractControlDescriptionProvider : 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
属性应用于Abstract控件。
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider))] public abstract class AbstractControl : UserControl ...
就是这样。 无需中间控制。
并且提供者类可以在同一解决方案中应用于我们想要的尽可能多的抽象基础。
解决此问题的另一种方法是使用预处理指令。
#if DEBUG public class UserControlAdmonEntidad : UserControl, IAdmonEntidad #else public abstract class UserControlAdmonEntidad : UserControl, IAdmonEntidad #endif { ... #if DEBUG public virtual object DoSomething() { throw new NotImplementedException("This method must be implemented!!!"); } #else public abstract object DoSomething(); #endif ... }
有关此主题的更多信息,请参阅此链接: 从抽象类inheritance表单(并使其在Designer中工作)
在这个MSDN论坛post中也提到了相同的解决方案,简单明了: UserControl,Inherited Control,Abstract class,(C#)
也许不是更清洁的解决方案,但它仍然是我找到的最短的解决方案。
以下是一个适合我的通用解决方案。 它基于另一个答案的文章 。 有时它会工作,我可以设计我的UserControl
,然后我将打开文件,它将给出“设计者必须创建一个类型’MyApp.UserControlBase’的实例,但它不能,因为该类型被声明为抽象“。 我想我可以通过清理,关闭VS,重新打开VS和重建来解决它。 现在它似乎表现得很好。 祝好运。
namespace MyApp { using System; using System.ComponentModel; /// /// Replaces a class of with a class of /// during design. Useful for /// replacing abstract s with mock concrete /// subclasses so that designer doesn't complain about trying to instantiate /// abstract classes (designer does this when you try to instantiate /// a class that derives from the abstract . /// /// To use, apply a to the /// class , and instantiate the attribute with /// SwitchTypeDescriptionProvider{T, TReplace})
. /// /// Eg: /// /// [TypeDescriptionProvider(typeof(ReplaceTypeDescriptionProvider{T, TReplace}))] /// public abstract class T /// { /// // abstract members, etc /// } /// /// public class TReplace : T /// { /// // Implement 's abstract members. /// } ///
/// /// /// /// The type replaced, and the type to which the /// must be /// applied /// /// /// The type that replaces . /// class ReplaceTypeDescriptionProvider : TypeDescriptionProvider { public ReplaceTypeDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(T))) { // Nada } public override Type GetReflectionType(Type objectType, object instance) { if (objectType == typeof(T)) { return typeof(TReplace); } return base.GetReflectionType(objectType, instance); } public override object CreateInstance( IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { if (objectType == typeof(T)) { objectType = typeof(TReplace); } return base.CreateInstance(provider, objectType, argTypes, args); } } }
即使这个问题已经存在多年了,我还想补充一下我发现的问题。
如果您不想触摸抽象基类,可以执行以下操作:
abstract class CustomControl : UserControl { protected abstract int DoStuff(); } class BaseDetailControl : CustomControl { protected override int DoStuff() { throw new InvalidOperationException("This method must be overriden."); } } class DetailControl : BaseDetailControl { protected override int DoStuff() { // do stuff return result; } }
这样,您的表单inheritance自非抽象的基本表单,并在设计器中显示! 而且你保留了抽象forms,但inheritance中只有一个级别。 奇怪,不是吗?
我不能把工作解决’Nicole Calinoiu’。 但是直接在visual studio中有另一种简单的方法:)
- 创建新项目
- 添加新元素’userControl’并添加一个按钮
- 添加新元素’userControl’Inhereted UserControl然后选择固有的userControl。
更多细节:’ http : //www.codeproject.com/Articles/20845/How-to-derive-from-a-parent-form
我只是将抽象基类定义为具体的,将“抽象”方法定义为虚拟,并在其中抛出exception,以防任何顽皮的派生类尝试调用Base实现。
例如
class Base : UserControl { protected virtual void BlowUp() { throw new NotSupportedException("This method MUST be overriden by ALL derived classes."); } class Derived : Base { protected override void BlowUp() { // Do stuff, but don't call base implementation, // just like you wouldn't (can't actually) if the Base was really abstract. // BTW - doesn't blow up any more ;) }
这与实际抽象基类之间的主要实际区别是,在调用基本实现时会出现运行时错误 – 而如果Base实际上是抽象的,则编译器将禁止意外调用Base类实现。 这对我来说不是什么大问题,并允许我使用设计师而不必担心其他人提出的更复杂和耗时的工作……
PS – Akuma – 您应该能够在设计器中编辑您的抽象UI类。 我现在没时间检查这个,但我的理解是设计者只需要实例化BASE类。 只要您正在设计的类的基础是具体的,设计类是什么并不重要。
我在自定义控件中解决了UWP中的这个问题。
我的情况
public abstract class BaseModel : DependencyObject { ... } public class MainModel : BaseModel { public bool ShowLabel { get{ return (bool)GetValue(ShowLabelProperty); } set{ SetValue(ShowLabelProperty, value) } } public static readonly DependencyProperty ShowLabelProperty = DependencyProperty.Register("ShowLabel",typeof(bool), typeof(MainModel), new PropertyMetadata(false)); }
宣言
< MyCustomControl:MainModel ShowLabel=True />
解
只需覆盖通用资源中的虚拟样式即可。
问候,
塞缪尔
我是UWP的新手,这让我疯狂。 我没有想到UserControl的抽象基类。 我走向了另一个方向。 我创建了一个非xaml Helper类… HBase
。 每个视图,比如VContract
,都有一个名为HContract
的对应Helper。 每个视图的所有专业代码都存放在那里。 ViewModel VMContract
和View VContract
之间的VContract
现在通过HContract
传递。 我们可以强制执行HWhatever
行为。 这不是OP问题的真正答案,但确实显示了另一种方法。 所有的视图现在基本上都是贝壳。 您是否x:绑定到VContract
或HContract
是您的决定。 我选择了VContract
方式,最后我认为这是一个错误。
设计模式中的exceptionUWP问题现在可以通过以下方式轻松解决:
if (false == Windows.ApplicationModel.DesignMode.DesignModeEnabled) { HContract = new HContract(this); // Put code here that fails in Design mode but must at run time }