Herencia abstracta de UserControl en el diseñador de Visual Studio

abstract class CustomControl : UserControl { protected abstract int DoStuff(); } class DetailControl : CustomControl { protected override int DoStuff() { // do stuff return result; } } 

Dejé un DetailControl en un formulario. Se representa correctamente en tiempo de ejecución, pero el diseñador muestra un error y no se abrirá porque el control del usuario base es abstracto.

Por el momento, estoy contemplando el siguiente parche, lo que me parece bastante malo, ya que quiero que las clases secundarias se vean obligadas a implementar el método.

 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; } } 

¿Alguien tiene una mejor idea sobre cómo solucionar este problema?

Puede usar TypeDescriptionProviderAttribute para proporcionar una implementación concreta en tiempo de diseño para su clase base abstracta. Ver http://wonkitect.wordpress.com/2008/06/20/using-visual-studio-whidbey-to-design-abstract-forms/ para más detalles.

Lo que nosotros queremos

Primero, definamos la clase final y la clase abstracta base.

 public class MyControl : AbstractControl ... public abstract class AbstractControl : UserControl // Also works for Form ... 

Ahora todo lo que necesitamos es un proveedor de descripción .

 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); } } 

Finalmente, solo aplicamos un atributo TypeDescriptionProvider al control Abstract.

 [TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider))] public abstract class AbstractControl : UserControl ... 

Y eso es. No se requiere control medio.

Y la clase de proveedor puede aplicarse a tantas bases abstractas como deseemos en la misma solución.

Otra forma de resolver esto es usar directivas de preprocesamiento.

 #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 ... } 

Consulte este enlace para obtener más información sobre este tema: Heredar un formulario de una clase abstracta (y hacer que funcione en el diseñador)

La misma solución también se mencionó en este hilo de foro de MSDN, de una manera más breve: UserControl, control heredado, clase abstracta, (C #)

Tal vez no es la solución más limpia, pero sigue siendo la más corta que he encontrado.

La siguiente es una solución genérica que funciona para mí, principalmente. Está basado en el artículo de otra respuesta. Algunas veces funcionará, y puedo diseñar mi UserControl , y luego abriré el archivo y aparecerá “El diseñador debe crear una instancia de tipo ‘MyApp.UserControlBase’ pero no puede porque el tipo se declara como abstracto. ” Creo que puedo solucionarlo limpiando, cerrando VS, volviendo a abrir VS y reconstruyendo. En este momento parece estar comportándose. Buena suerte.

 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); } } } 

Aunque esta pregunta tiene muchos años, me gustaría agregar lo que he encontrado.

Si no quiere tocar su clase base abstracta, puede hacer esto:

 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; } } 

De esta forma, su formulario hereda de una forma base no abstracta y se muestra en el diseñador. Y mantienes tu forma abstracta, pero solo un nivel más en la herencia. Extraño, ¿verdad?

No pude hacer del trabajo la solución de ‘Nicole Calinoiu’. Pero hay otra manera fácil directamente en visual studio 🙂

  1. Crear nuevo proyecto
  2. Agregue el nuevo elemento ‘userControl’ y agregue un botón, por ejemplo
  3. Agregue el nuevo elemento ‘userControl’ UserControl ingresado y luego seleccione userControl.

Más detalles aquí: ‘ http://www.codeproject.com/Articles/20845/How-to-derive-from-a-parent-form

Solo hago que la clase base abstracta se convierta en una concreta al definir los métodos “abstractos” como virtuales y lanzando una excepción en ellos, en caso de que alguna clase derivada trate de llamar a la implementación de Base.

p.ej

  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 ;) } 

La principal diferencia práctica entre esta y una clase base abstracta real es que obtiene errores de tiempo de ejecución al invocar la implementación base, mientras que si la Base era realmente abstracta, el comstackdor no permitiría realizar llamadas accidentales a la implementación de la Clase base. Lo cual no es gran cosa para mí y me permite usar el diseñador sin preocuparme por el trabajo más complejo y lento que sugieren otros …

PD: Akuma: debería poder editar su clase abstracta de interfaz de usuario en el diseñador. No tengo tiempo para verificar esto ahora, pero tengo entendido que el diseñador solo necesita crear una instancia de la clase BASE. Siempre que la base de la clase que está diseñando sea concreta, no importa cuál sea la clase diseñada.

Resolví este problema en UWP en mi control personalizado.

Mi caso

 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)); } 

Declaración

 < MyCustomControl:MainModel ShowLabel=True /> 

Solución

Simplemente anule un estilo ficticio en los recursos generics.

  

Saludos,

Samuel

Era nuevo en esto en UWP y me estaba volviendo loco. No pensé en una clase base abstracta para UserControl. Fui en una dirección diferente. Creé una clase de ayuda no xaml … HBase . Cada Vista, digamos VContract , tenía un Ayudante correspondiente llamado HContract . Todo el código de especialidad para cada vista se alojó allí. Las conversaciones que habrían tenido lugar entre ViewModel VMContract y View VContract ahora pasan a través de HContract . Podemos hacer cumplir cómo HWhatever comporta con IHBase . No es realmente una respuesta a la pregunta del OP, pero muestra un enfoque alternativo. Todas las Vistas ahora son básicamente conchas. Si usted x: VContract a VContract o HContract es una decisión que debe tomar. Elegí la forma VContract y al final creo que fue un error.

El problema de UWP con excepciones en el modo de diseño ahora se soluciona fácilmente con:

 if (false == Windows.ApplicationModel.DesignMode.DesignModeEnabled) { HContract = new HContract(this); // Put code here that fails in Design mode but must at run time }