Comment puis-je appliquer le modèle MVC à une application C # WinForms?


11

Je suis un développeur C ++ qui utilise depuis le modèle MVC pour concevoir des interfaces graphiques.

Récemment, je voulais revenir en C #, et j'ai installé une application Windows Forms, mais maintenant je suis un peu perdu sur la façon de le pousser vers une structure compatible MVC.

Ce que j'essaie actuellement de faire, c'est de «déclarer» la classe que l'on me donne pour les WinForms en tant que vue et d'ajouter une classe pour le modèle et le contrôleur en arrière-plan. Cependant, je ne suis pas vraiment sûr de la façon d'interagir avec les événements, comme un clic sur un bouton. Habituellement, je redirige ces événements vers le contrôleur et exécute une action sur la vue une fois que j'ai terminé.

Cela semble assez insatisfaisant dans cette constellation. Par exemple, si je voulais implémenter un bouton "Quitter", je devrais rediriger l'événement de la vue vers le contrôleur, ainsi que mettre en œuvre une méthode publique supplémentaire dans ma vue qui peut ensuite être appelée depuis le contrôleur, tandis que je pourrait simplement appeler Close () à partir de la vue dans la première instance.

Avez-vous des conseils pour moi? Ma compréhension des formulaires Windows en C # n'est-elle pas encore assez bonne pour essayer une implémentation MVC? Suis-je en train de donner un mauvais rôle à la classe de formulaires? MVC est-il simplement une architecture inappropriée pour ce cas d'utilisation?


1
Question OT. Mais pourquoi WInforms? WPF était destiné à remplacer Winforms et prend en charge MVC (Eh bien techniquement MVVM). Bien que je dirai que la courbe d'apprentissage WPF peut être abrupte. (mais si vous le faites mal, vous pouvez faire ressembler le code WPF à Winforms)
Peter M

1
@PeterM: parce que même après 10 ans, WPF craint et est toujours lent.
whatsisname

3
Pour paraphraser le commentaire de @ whatsisname, WPF est orienté vers des applications plus grandes. Les petites applications pourraient être mieux servies avec Winforms car Winforms est sans doute plus simple. Cependant, si vous voulez faire cet argument, vous pouvez également faire valoir que votre application Winforms est suffisamment petite là où elle n'a probablement pas besoin de MVP de toute façon. MVVM est intégré dans WPF. WPF a des graphiques vectoriels, il ne souffre donc pas des mêmes problèmes de dimensionnement que Winforms. WPF est très composable (vous pouvez facilement placer des contrôles dans d'autres contrôles), et il a une liaison de données tueur. Qu'est-ce qu'il ne faut pas aimer?
Robert Harvey

3
@whatsisname WPF peut être nul, mais il aspire beaucoup moins que Winforms pour quoi que ce soit au-delà d'un programme de jouets
Peter M

2
Pour les programmes de bureau internes, je dirais que oui. Mais de nombreuses entreprises préfèrent les applications basées sur un navigateur pour leurs opérations commerciales, simplement parce qu'aucune installation n'est requise.
Robert Harvey

Réponses:


3

Par coïncidence, je travaille sur un projet WinForms qui est calqué sur MVC. Je n'appellerais pas cela une réponse parfaite, mais je vais expliquer ma conception globale et j'espère que cela peut vous aider à trouver votre propre.

Sur la base de la lecture que j'ai faite avant de commencer ce projet, il ne semble pas y avoir de "bonne" façon de mettre cela en œuvre. J'ai suivi des principes de conception OOP et MVC simples et le reste a été un essai et une erreur lorsque j'ai développé un flux de travail.

MVC est-il simplement une architecture inappropriée pour ce cas d'utilisation?

Non ..? Il n'y a pas assez de contexte dans votre question pour y répondre directement. Pourquoi utilisez-vous MVC en premier lieu? Quelles sont les exigences non fonctionnelles de votre projet? Votre projet va-t-il être très lourd en interface utilisateur? Vous vous souciez davantage de la sécurité et préférez une architecture en couches? Quelles sont les principales composantes de votre projet? Peut-être que chaque composant a besoin d'un modèle de conception différent. Découvrez pourquoi vous souhaitez utiliser ce modèle de conception en premier lieu et vous pourriez répondre à votre propre question;)

Ma raison d'utiliser MVC: c'est un modèle de conception assez simple à comprendre à mon avis et ma conception est fortement basée sur l'interaction avec l'utilisateur. La façon dont MVC permet au développeur de séparer ses préoccupations est également suffisante pour mon application. Cela rend mon code beaucoup plus maintenable et testable.

Je suppose également que j'utilise davantage une conception hybride. Habituellement, le concept idéal présenté en génie logiciel ne se concrétise pas dans la pratique. Vous pouvez modifier la conception en fonction des besoins de votre projet. Pas besoin de se laisser entraîner dans ce qui est bien ou mal. Il existe des pratiques générales, mais les règles peuvent toujours être pliées ou brisées tant que vous ne vous tirez pas une balle dans le pied.

Mon implémentation a commencé par une conception de haut niveau qui m'a donné une idée des composants dont j'ai besoin. Il est préférable de commencer de cette façon et de descendre dans l'architecture. Voici le diagramme de package pour le projet (créé dans StarUML): entrez la description de l'image ici

Notez que chaque couche, sauf la couche de présentation, dépend du système de messagerie. Il s'agit d'un "langage" commun que les couches inférieures et les sous-systèmes de ces couches utilisent pour communiquer entre eux. Dans mon cas, il s'agissait d'une simple énumération basée sur des opérations pouvant être effectuées. Ce qui m'amène au point suivant...

Considérez les opérations ou les commandes comme la base de votre implémentation. Que voulez-vous que votre application fasse? Décomposez-le en opérations les plus fondamentales. Par exemple: CreateProject, WriteNotes, SaveProject, LoadProject etc. L'interface graphique (ou les classes de formulaire) va se produire un événement (comme une pression sur un bouton). Chaque opération est associée à une méthode de contrôleur. Dans ce cas, quelque chose comme Exit est trop simple. L'application peut simplement être fermée de la classe Form. Mais supposons que je veuille d'abord conserver certaines données d'application dans un fichier? J'appellerai la méthode "Save" de la classe de contrôleur respective dans ma méthode de pression de bouton.

À partir de là, le contrôleur appellera le bon ensemble d'opérations à partir des classes de service. Les classes de service dans mon application agissent comme une interface avec la couche domaine. Ils valideront les entrées reçues de l'appel de méthode du contrôleur (et donc de l'interface graphique) et manipuleront le modèle de données.

Une fois la validation et la manipulation d'objet correspondante terminées, la méthode de service renvoie un code de message au contrôleur. Par exemple MessageCodes.SaveSuccess,. Les classes de contrôleur et de service étaient basées sur les objets de domaine et / ou l'ensemble général d'opérations qui peuvent être regroupées.

Par exemple: FileMenuController(opérations: NewProject, SaveProject, LoadProject) -> ProjectServices(CreateProject, PersistProjectToFile, LoadProjectFromFile). Où Projectserait une classe de domaine dans votre modèle de données. Les classes Controller et Service dans mon cas étaient des classes non instanciables avec des méthodes statiques.

Ensuite, le contrôleur reconnaît que l'opération s'est terminée sans succès / avec succès. Désormais, le contrôleur possède son propre système de messagerie qu'il utilise pour interagir avec la couche de présentation, d'où la double dépendance entre les couches Service et Présentation. Dans ce cas, une classe appelée ViewStatedans le ViewModelspackage est toujours renvoyée à l'interface graphique par le contrôleur. Cet état contient des informations telles que: " l'état dans lequel vous avez essayé de mettre l'application en cours de validité? ", " Un message lisible par l'utilisateur sur l'opération que vous avez tenté d'exécuter et pourquoi elle a réussi ou échoué (messages d'erreur) " et une ViewModelclasse.

La ViewModelclasse contient des données pertinentes de la couche de domaine que l'interface graphique utilisera pour mettre à jour la vue. Ces modèles de vues ressemblent aux classes de domaine mais dans mon cas, j'ai utilisé des objets très maigres . Fondamentalement, ils n'ont pratiquement aucun comportement, relaient simplement des informations sur l'état de niveau inférieur de l'application. En d'autres termes, je ne vais JAMAIS donner mes classes de domaine à la couche de présentation. C'est aussi pourquoi les packages Controllerset Servicesdivisent la couche de service en deux parties. Les contrôleurs ne géreront jamais les classes de domaine ni ne valideront leur état. Ils agissent simplement comme une frontière convertissant les données pertinentes de l'interface graphique en données pertinentes pour le domaine que les services peuvent utiliser et vice-versa. Y compris la logique de service dans le contrôleur conduirait à très gras contrôleurs, qui sont plus difficiles à entretenir.

J'espère que cela vous donne un point de départ.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.