Model-View-Presenter dans WinForms

J’essaie d’implémenter la méthode MVP pour la première fois, en utilisant WinForms.

J’essaie de comprendre la fonction de chaque couche.

Dans mon programme, j’ai un bouton GUI qui, une fois cliqué, ouvre une fenêtre openfiledialog.

Ainsi, en utilisant MVP, l’interface graphique gère l’événement click du bouton, puis appelle presenter.openfile ();

Dans le fichier presenter.openfile (), devrait-il alors déléguer l’ouverture de ce fichier à la couche modèle, ou s’il n’ya pas de données ou de logique à traiter, doit-il simplement agir sur la requête et ouvrir la fenêtre openfiledialog?

Mise à jour: J’ai décidé d’offrir une prime car j’estime que j’ai besoin d’une aide supplémentaire à ce sujet, et de préférence adaptée à mes points spécifiques ci-dessous, afin d’avoir un contexte.

Bon, après avoir lu sur MVP, j’ai décidé de mettre en place la vue passive. Effectivement, je vais avoir un tas de contrôles sur une Winform qui sera traitée par un présentateur, puis les tâches déléguées au (x) modèle (s). Mes points spécifiques sont ci-dessous:

  1. Lorsque la winform se charge, il doit obtenir un treeview. Ai-je raison de penser que la vue devrait donc appeler une méthode telle que: presenter.gettree (), qui à son tour déléguera au modèle, qui obtiendra les données pour l’arborescence, la créera et la configurera, la renverra au présentateur, qui à son tour passera à l’opinion qui l’atsortingbuera alors simplement, disons, à un panel?

  2. Est-ce que ce serait la même chose pour tout contrôle de données sur le Winform, car j’ai aussi un datagridview?

  3. Mon application, a un certain nombre de classes de modèle avec le même assemblage. Il prend également en charge une architecture de plug-in avec des plug-ins qui doivent être chargés au démarrage. La vue appelle-t-elle simplement une méthode de présentateur, qui à son tour appelle une méthode qui charge les plug-ins et affiche les informations dans la vue? Quel niveau contrôlerait alors les références du plugin. La vue contiendrait-elle des références à eux ou au présentateur?

  4. Ai-je raison de penser que la vue devrait gérer chaque élément de la présentation, de la couleur du nœud de l’arborescence à la taille de la grid de données, etc.?

Je pense que ce sont mes principales préoccupations et si je comprends comment le stream devrait être pour ceux-ci, je pense que je vais bien.

Ceci est mon humble avis sur MVP et vos problèmes spécifiques.

Tout d’abord , tout ce qu’un utilisateur peut interagir ou simplement afficher est une vue . Les lois, le comportement et les caractéristiques d’une telle vue sont décrits par une interface . Cette interface peut être implémentée en utilisant une interface utilisateur WinForms, une interface utilisateur de console, une interface utilisateur Web ou même aucune interface utilisateur (généralement lors du test d’un présentateur) – l’implémentation concrète n’a pas d’importance tant qu’elle respecte les lois de son interface .

Deuxièmement , une vue est toujours contrôlée par un présentateur . Les lois, le comportement et les caractéristiques d’un tel présentateur sont également décrits par une interface . Cette interface n’a aucun intérêt dans l’implémentation de la vue concrète tant qu’elle obéit aux lois de son interface de vue.

Troisièmement , comme un présentateur contrôle sa vue, pour minimiser les dépendances, il n’y a vraiment aucun gain à ce que la vue ne sache rien du présentateur. Il y a un contrat convenu entre le présentateur et la vue et qui est indiqué par l’interface de vue.

Les implications de Third sont:

  • Le présentateur ne dispose d’aucune méthode que la vue peut appeler, mais la vue comporte des événements auxquels le présentateur peut s’abonner.
  • Le présentateur connaît son sharepoint vue. Je préfère réaliser ceci avec l’injection de constructeur sur le présentateur concret.
  • La vue n’a aucune idée de ce que le présentateur contrôle; il ne sera jamais fourni aucun présentateur.

Pour votre problème, ce qui précède pourrait ressembler à ceci dans un code quelque peu simplifié:

interface IConfigurationView { event EventHandler SelectConfigurationFile; void SetConfigurationFile(ssortingng fullPath); void Show(); } class ConfigurationView : IConfigurationView { Form form; Button selectConfigurationFileButton; Label fullPathLabel; public event EventHandler SelectConfigurationFile; public ConfigurationView() { // UI initialization. this.selectConfigurationFileButton.Click += delegate { var Handler = this.SelectConfigurationFile; if (Handler != null) { Handler(this, EventArgs.Empty); } }; } public void SetConfigurationFile(ssortingng fullPath) { this.fullPathLabel.Text = fullPath; } public void Show() { this.form.ShowDialog(); } } interface IConfigurationPresenter { void ShowView(); } class ConfigurationPresenter : IConfigurationPresenter { Configuration configuration = new Configuration(); IConfigurationView view; public ConfigurationPresenter(IConfigurationView view) { this.view = view; this.view.SelectConfigurationFile += delegate { // The ISelectFilePresenter and ISelectFileView behaviors // are implicit here, but in a WinForms case, a call to // OpenFileDialog wouldn't be too far fetched... var selectFilePresenter = Gimme.The(); selectFilePresenter.ShowView(); this.configuration.FullPath = selectFilePresenter.FullPath; this.view.SetConfigurationFile(this.configuration.FullPath); }; } public void ShowView() { this.view.SetConfigurationFile(this.configuration.FullPath); this.view.Show(); } } 

En plus de ce qui précède, j’ai généralement une interface IView base où je range le Show() et toute vue propriétaire ou vue de titre dont mes vues bénéficient généralement.

À vos questions:

1. Lorsque la winform est chargée, elle doit obtenir un treeview. Ai-je raison de penser que la vue devrait donc appeler une méthode telle que: presenter.gettree (), qui à son tour déléguera au modèle, qui obtiendra les données pour l’arborescence, la créera et la configurera, la renverra au présentateur, qui à son tour passera à l’opinion qui l’atsortingbuera alors simplement, disons, à un panel?

J’appellerais IConfigurationView.SetTreeData(...) de IConfigurationPresenter.ShowView() , juste avant l’appel à IConfigurationView.Show()

2. Est-ce que ce serait la même chose pour tout contrôle de données sur le Winform, car j’ai aussi un datagridview?

Oui, j’appellerais IConfigurationView.SetTableData(...) pour cela. C’est à la vue de formater les données qui lui sont données. Le présentateur obéit simplement au contrat de la vue selon lequel il souhaite des données tabulaires.

3. Mon application contient plusieurs classes de modèle avec le même assemblage. Il prend également en charge une architecture de plug-in avec des plug-ins qui doivent être chargés au démarrage. La vue appelle-t-elle simplement une méthode de présentateur, qui à son tour appelle une méthode qui charge les plug-ins et affiche les informations dans la vue? Quel niveau contrôlerait alors les références du plugin. La vue contiendrait-elle des références à eux ou au présentateur?

Si les plug-ins sont liés à la vue, les vues doivent les connaître, mais pas le présentateur. S’ils concernent tous des données et des modèles, la vue ne devrait pas avoir de lien avec eux.

4. Ai-je raison de penser que la vue devrait gérer chaque élément de la présentation, de la couleur du nœud de l’arborescence à la taille de la grid de données, etc.?

Oui. Pensez-y comme le présentateur fournissant XML qui décrit les données et la vue qui prend les données et applique une feuille de style CSS à celle-ci. Concrètement, le présentateur peut appeler IRoadMapView.SetRoadCondition(RoadCondition.Slippery) et la vue affiche alors la route en rouge.

Qu’en est-il des données pour les nœuds cliqués?

5. Si je clique sur les treenodes, dois-je passer par le nœud spécifique au présentateur et ensuite, le présentateur déterminera les données dont il a besoin et demandera ensuite le modèle pour ces données, avant de les présenter à la vue?

Si possible, je transmettrais toutes les données nécessaires pour présenter l’arbre dans une vue en une seule fois. Mais si certaines données sont trop grandes pour être transmises depuis le début ou si elles sont dynamics par nature et ont besoin du “dernier cliché” du modèle (via le présentateur), j’appendai quelque chose comme l’ event LoadNodeDetailsEventHandler LoadNodeDetails à l’interface Pour que le présentateur puisse s’y abonner, récupérez les détails du nœud dans LoadNodeDetailsEventArgs.Node (éventuellement via son identifiant quelconque) à partir du modèle, de sorte que la vue puisse mettre à jour les détails du nœud affiché lors du retour du délégué du gestionnaire d’événements. Notez que des modèles asynchrones peuvent être nécessaires si l’extraction des données est trop lente pour une bonne expérience utilisateur.

Le présentateur, qui contient toute la logique de la vue, devrait répondre au clic sur le bouton, comme le dit @JochemKempe. En termes pratiques, le bouton cliquez sur le gestionnaire d’événements pour appeler presenter.OpenFile() . Le présentateur est alors en mesure de déterminer ce qui doit être fait.

S’il décide que l’utilisateur doit sélectionner un fichier, il renvoie dans la vue (via une interface de vue) et laisse la vue, qui contient toutes les OpenFileDialog techniques de l’interface utilisateur, afficher OpenFileDialog . Il s’agit d’une distinction très importante en ce sens que le présentateur ne devrait pas être autorisé à effectuer des opérations liées à la technologie de l’interface utilisateur utilisée.

Le fichier sélectionné sera alors renvoyé au présentateur qui continue sa logique. Cela peut impliquer n’importe quel modèle ou service devant traiter le fichier.

La principale raison d’utiliser un modèle MVP, imo est de séparer la technologie d’interface utilisateur de la logique d’affichage. Ainsi, le présentateur orchestre toute la logique alors que la vue la sépare de la logique de l’interface utilisateur. Cela a pour effet secondaire de rendre le présentateur entièrement testable.

Mise à jour: dans la mesure où le présentateur est l’incarnation de la logique trouvée dans une vue spécifique , la relation entre le présentateur et la vue est une relation un à un. Et à toutes fins pratiques, une instance de vue (par exemple un formulaire) interagit avec une instance de présentateur et une instance de présentateur interagit avec une seule instance de vue.

Cela dit, dans mon implémentation de MVP avec WinForms, le présentateur interagit toujours avec la vue via une interface représentant les capacités de l’interface utilisateur de la vue. Il n’y a pas de limitation sur la vue qui implémente cette interface, ainsi différents “widgets” peuvent implémenter la même interface de vue et réutiliser la classe présentateur.

Le présentateur doit agir à la fin de la requête pour afficher la fenêtre openfiledialog comme vous l’avez suggéré. Comme aucune donnée n’est requirejse du modèle, le présentateur peut et doit gérer la demande.

Supposons que vous ayez besoin des données pour créer des entités dans votre modèle. Vous pouvez soit transmettre le stream à la couche d’access où vous avez une méthode pour créer des entités à partir du stream, mais je vous suggère de traiter l’parsing du fichier dans votre présentateur et d’utiliser un constructeur ou une méthode Create par entité dans votre modèle.