105 votes

Comment puis-je obtenir Visual Studio 2008 concepteur Windows Forms pour rendre un Formulaire qui implémente une classe de base abstraite?

J'ai engagé un problème avec un héritage de Contrôles Windows Forms et besoin de quelques conseils.

J'utilise une classe de base pour les éléments d'une Liste (selfmade GUI liste faite d'un panneau) et certaines sont héritées de contrôles pour chaque type de données qui peut être ajouté à la liste.

Il n'y a pas de problème avec elle, mais maintenant, je trouve, que ce serait bon, pour en faire la base de contrôle d'une classe abstraite, car il a des méthodes, qui doivent être mis en œuvre dans tous hérité de contrôle, appelée à partir du code à l'intérieur de la base de contrôle, mais ne doit pas et ne peut pas être mis en œuvre dans la classe de base.

Quand je marque la base de contrôle de l'abstraction, le Visual Studio 2008 Designer refuse de charger la fenêtre.

Est-il un moyen pour obtenir le Concepteur de travailler avec la base de contrôle abstraites?

103voto

smelch Points 1317

Je SAVAIS qu'il y avait un moyen de le faire (et j'ai trouvé le moyen de le faire proprement). Sheng solution est exactement ce que j'ai trouvé comme solution temporaire, mais après un ami a souligné que l' Form classe finalement hérité d'un abstract classe, nous DEVRIONS être en mesure d'obtenir ce fait. Si ils peuvent le faire, nous pouvons le faire.

Nous sommes allés à partir de ce code pour le problème

Form1 : Form

Problème

public class Form1 : BaseForm
...
public abstract class BaseForm : Form

C'est là que la question initiale est entré en jeu. Comme dit avant, un ami l'a souligné qu' System.Windows.Forms.Form implémente une classe de base abstraite. Nous avons été en mesure de trouver...

La preuve d'une meilleure solution

À partir de cela, nous savions qu'il était possible pour le concepteur de montrer une classe qui a mis en œuvre une base de classe abstraite, on ne pouvait tout simplement pas montrer une classe de concepteur qui a immédiatement mis en place une base de classe abstraite. Il en fallait au max 5 entre les deux, mais nous avons testé 1 couche d'abstraction et d'abord venu avec cette solution.

Solution Initiale

public class Form1 : MiddleClass
...
public class MiddleClass : BaseForm
... 
public abstract class BaseForm : Form
... 

Cela fonctionne et le designer rend bien, le problème est résolu.... sauf si vous avez un niveau supplémentaire de l'héritage dans votre application de production qui a été nécessaire en raison d'une insuffisance dans les winforms designer!

Ce n'est pas 100% infaillible solution, mais son assez bon. Fondamentalement, vous utilisez #if DEBUG à venir avec le raffinement de la solution.

Raffiné Solution

Form1.cs

#if DEBUG
public class Form1 : MiddleClass
#else 
public class Form1 : BaseForm
#endif
...

Classe moyenne.cs

public class MiddleClass : BaseForm
... 

La classe baseform.cs

public abstract class BaseForm : Form
... 

Ce que cela fait, c'est seulement l'utilisation de la solution décrite dans la section "solution initiale", si il est en mode de débogage. L'idée est que vous ne publiez jamais le mode de production via une version debug et que vous serez toujours la conception en mode de débogage.

Le concepteur fonctionnera toujours à l'encontre du code construit dans le courant de la mode, de sorte que vous ne pouvez pas utiliser le concepteur en mode release. Toutefois, aussi longtemps que vous le design en mode debug et release le code intégré dans la version de la mode, vous êtes bon pour aller.

La seule solution infaillible, si vous pouvez tester le mode de conception par l'intermédiaire d'une directive de préprocesseur.

85voto

Juan Carlos Diaz Points 315

@smelch, Il y a une meilleure solution, sans avoir à créer un moyen de contrôle, de même pour le débogage.

Ce que nous voulons

Tout d'abord, définissons la finale de la classe de base et la classe abstraite.

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

Maintenant, tous nous avons besoin est une Description fournisseur.

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

Enfin, nous il suffit d'appliquer un TypeDescriptionProvider attribut à la Abastract de contrôle.

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

Et c'est tout. Aucun moyen de contrôle requis.

Et le fournisseur de classe peut être appliquée à un nombre Abstrait bases que nous voulons dans la même solution.

11voto

Dave Clemmer Points 2448

@Smelch, merci pour la réponse utile, comme je l'ai été en cours d'exécution dans la même question récemment.

La suite est un changement mineur à votre post pour éviter des avertissements de compilation (en mettant la classe de base au sein de l' #if DEBUG pré-processeur de la directive):

public class Form1
#if DEBUG  
 : MiddleClass 
#else  
 : BaseForm 
#endif 

5voto

Jan Hettich Points 1504

J'ai eu un problème similaire, mais a trouvé un moyen de refactoriser choses à utiliser une interface à la place d'une classe de base abstraite:

interface Base {....}

public class MyUserControl<T> : UserControl, Base
     where T : /constraint/
{ ... }

Cela peut ne pas être applicables à toutes les situations, mais quand c'est possible, il en résulte une solution plus propre que la compilation conditionnelle.

3voto

Carl G Points 2025

Je suis en utilisant la solution dans cette réponse à une autre question, les liens de cet article. L'article recommande l'utilisation d'une coutume TypeDescriptionProvider et la mise en œuvre concrète de la classe abstraite. Le concepteur va demander au fournisseur personnalisé types à utiliser, et le code de retour de la classe de béton, de sorte que le concepteur est heureux alors que vous avez le contrôle complet sur la façon dont la classe abstraite apparaît comme une classe concrète.

Mise à jour: j'ai inclus une documentation de code de l'échantillon dans ma réponse à l'autre question. Le code fonctionne, mais parfois je dois passer par un nettoyage/cycle de production comme indiqué dans ma réponse à le faire fonctionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X