2009-08-04 7 views
2

Disons que nous avons cette interface:Comment créer des composants WinForms en fonction du type d'un objet

interface IVehicle { ... } 

Et des cours de mise en œuvre il:

class Car : IVehicle { ... } 
class Boat : IVehicle { ... } 
class Plane : IVehicle { ... } 

Dans mon interface utilisateur que j'ai un FlowLayoutPanel et l'accès à une sorte de IEnumerable<IVehicle> avec un certain nombre de divers objets IVehicle.

Maintenant, je veux créer un UserControl pour chacun des véhicules et l'ajouter au FlowLayoutPanel. Les commandes seront similaires, mais comme il y a des véhicules de différents types, certains contrôles peuvent avoir besoin d'être légèrement différents ou de travailler différemment pour que l'utilisateur puisse facilement travailler avec ses véhicules. Comment puis-je résoudre cela sans trop d'encombrement?

Répondre

2

Que diriez-vous en utilisant une sorte de méthode de création:

UserControl CreateControl(IVehicle vehicle) 
{ 
    if (vehicle is Car) 
    { 
     return new CarControl(); 
    } 
    else if (vehicle is Boat) 
    { 
     return new BoatControl(); 
    } 
    ... 
} 
+0

Je pense que ce serait l'option la plus simple, bien que j'espérais éviter une longue déclaration "if else if" ou "switch". Cela se terminera probablement avec ceci: p – Svish

1

Je ne sais pas exactement ce que vous visez, mais vous pouvez utiliser les médicaments génériques lorsque vous étendez les contrôles utilisateur de la manière habituelle:

public class VehicleControl<TVehicle>: UserControl 
where TVehicle:IVehicle 
{ 
    //do something specific with IVehicle 
} 

public class CarControl : VehicleControl<Car> 
{ 
    //add stuff specific for the Car 
} 
+0

Comment instancieriez-vous les contrôles? – Svish

+0

Je pourrais utiliser une méthode d'usine proposée par @Patrick McDonald dans sa réponse. Nos réponses sont gratuites. – Grzenio

+0

Ah, gothque. idée intéressante. – Svish

0

Si vous connaissez le code lors de l'écriture comment le mappage ressemble, vous pouvez configurer à Dictionary avec les correspondances:

private Dictionary<Type, Type> _vehicleToControlTypeMappings = new Dictionary<Type, Type>(); 

applications de charge au démarrage:

_vehicleToControlTypeMappings.Add(typeof(Car), typeof(CarControl)); 
_vehicleToControlTypeMappings.Add(typeof(Plane), typeof(PlaneControl)); 

... et fournir une méthode pour obtenir un nouveau contrôle basé sur un véhicule:

private Control GetVehicleControl(IVehicle vehicle) 
{ 
    Control result = (Control)Activator.CreateInstance(
     _vehicleToControlTypeMappings[(vehicle as object).GetType()] 
     ); 
    // perform additional initialization of the control 
    return result; 
} 

Ensuite, vous pouvez tout simplement passer des objets de types qui met en oeuvre en IVehicle la méthode:

IVehicle vehicle = new Car(); 
Control newctl = GetVehicleControl(vehicle); 
+0

Il semble chic et je pensais à quelque chose de similaire. Mais est-ce que ce n'est pas une manière complexe de faire ce que Patrick McDonald a fait dans sa réponse avec un «si autre chose»? – Svish

+0

La principale différence est que je pense que cette approche a une séparation plus nette des préoccupations; la méthode factory n'a aucune connaissance des mappings en tant que tels, elle effectue simplement une recherche.Cela signifie que vous pouvez modifier la façon dont le dictionnaire de mappage est rempli (par exemple, il peut être chargé en fonction des informations contenues dans un fichier de configuration) sans modifier la méthode d'usine. –

+2

Je pense que ce genre de complication n'a de sens que si vous prévoyez d'ajouter de nouvelles classes de véhicules assez souvent. – Grzenio

2

Dans votre interface IVehicle, vous pouvez ajouter une méthode pour obtenir le contrôle de l'utilisateur.

public interface IVehicle 
{ 
    UserControl GetVehicleControl(); 
} 

Si vous avez besoin d'un contrôle pour chaque véhicule, vous pouvez utiliser ce code:

public class Car : IVehicle 
{ 
    public UserControl GetVehicleControl() 
    { 
     return new CarControl(); 
    } 
} 

Sinon, si vous avez besoin d'une seule commande pour chaque type de véhicule:

public class Car : IVehicle 
{ 
    private static CarControl m_control; 

    public UserControl GetVehicleControl() 
    { 
     if(m_control == null) 
      m_control = new CarControl(); 

     return m_control; 
    } 
} 
+0

Pourquoi est-ce que CarControl est statique? Donc, plusieurs véhicules partagent le contrôle? – Scoregraphic

+0

@Scoregraphic: Oui dans le cas où un seul CarControl est nécessaire pour toutes les voitures. Mais je pense que l'OP veut un contrôle pour chaque voiture, bateau, etc ... donc la version sans variable statique est la meilleure. –

+0

Mais si je fais cela, les véhicules, qui sont à peu près des objets de gestion, devraient connaître leur représentation visuelle. Ce n'est pas très bon design, n'est-ce pas? – Svish

Questions connexes