Présentateur modèle C # WinForms (présentation passive)

Je développe une application WinForms en C #. J’ai une expérience limitée dans la programmation d’interface graphique et j’ai beaucoup à apprendre à la volée. Cela étant dit, voici ce que je construis.

Voir l’interface graphique générale sur le lien suivant:

GUI http://img227.imageshack.us/img227/1084/program0.jpg

Maintenant, j’ai déjà effectué une bonne partie du travail, mais dans le très mauvais modèle de conception autonome. Je ne savais pas que le projet atteindrait jamais une certaine taille et, en tant que tel, il est temps de procéder à une refactorisation majeure.

J’ai beaucoup étudié les modèles de conception d’interface graphique et le modèle que je souhaite implémenter est la vue passive (voir http://martinfowler.com/eaaDev/PassiveScreen.html ). Je cherche de l’aide sur la façon de réunir tout cela.

Contexte:

1) Selon ce que l’utilisateur clique dans “TreeView”, la “Liste” située dans le coin inférieur gauche affiche une liste d’objects pouvant remplir la zone “Editeur”. Ces objects peuvent être une zone de texte ou un DataGridView. L’utilisateur bascule la liste pour choisir ce qu’il / elle veut voir dans “l’éditeur”

2) Le modèle est essentiellement un dossier avec des fichiers de données et de configuration. Il existe un programme externe qui s’exécute sur un répertoire donné, crée des fichiers de sortie / dossiers, etc. Ce programme que je développe est conçu pour gérer / configurer efficacement ces objects de manière conviviale.

3) Le problème avec ma façon de faire les choses est qu’il est presque impossible de tester, et par conséquent le passage au modèle de conception MVP-esque Passive View

J’essaie de faire en sorte que le programme fonctionne indépendamment de la vue. Je n’ai pas trouvé d’exemples où une vue interactive plus complexe est utilisée avec le modèle de vue passive.

Des questions:

1) Dois-je implémenter une grande interface / vue pour l’ensemble du “look” du programme, puis des sous-interfaces / sous-vues pour chacune des vues TreeView, Editor, Logger, etc.? Ou existe-t-il une meilleure “structure” pour ce faire?

2) Pour ce qui est de “transférer” des événements de la vue au présentateur / contrôleur (quelle que soit la terminologie que vous souhaitez utiliser, le modèle de conception de vue passive), comment dois-je procéder? Parfois, j’ai des propriétés simples qui doivent être mises à jour et parfois, il me faut toute une série d’étapes à déployer.

J’aimerais des suggestions et des conseils sur ce sujet. J’ai parcouru Internet et je n’ai pas trouvé d’exemples suffisants pour m’aider à poursuivre ce projet.

Merci d’avance!

Daniel

Voici un exemple simple qui illustre le concept de vues passives à l’aide du modèle de conception MVP. Comme nous utilisons des vues passives, la vue n’a aucune connaissance du présentateur. Le présentateur s’abonnera simplement aux événements publiés par la vue et agira en conséquence.

Pour commencer, nous devons définir un contrat pour notre sharepoint vue. Ceci est généralement réalisé en utilisant une interface, essentiellement, nous voulons avoir un couplage très lâche avec notre vue. Nous voulons pouvoir changer de vue ou créer des vues fantômes pour les tests unitaires.

Voici un contrat qui décrit une vue simple qui sera utilisée pour afficher les informations client

public interface ICustomerManagementView { void InitializeCustomers(ICustomer[] customers); void DisplayCustomer(ICustomer customer); event EventHandler> SelectedCustomerChanged; } 

Il expose une seule méthode InitializeCustomers qui sera utilisée pour initialiser notre vue avec des objects de notre modèle.

Nous avons également un événement SelectedCustomerChanged qui sera utilisé par notre présentateur pour recevoir une notification indiquant qu’une action a eu lieu dans la vue.

Une fois que nous avons notre contrat, nous pouvons commencer à gérer ces interactions dans notre présentateur.

 public class CustomerManagementPresenter { private ICustomer _selectedCustomer; private readonly ICustomerManagementView _managementView; private readonly ICustomerRepository _customerRepository; public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository) { _managementView = managementView; _managementView.SelectedCustomerChanged += this.SelectedCustomerChanged; _customerRepository = customerRepository; _managementView.InitializeCustomers(_customerRepository.FetchCustomers()); } private void SelectedCustomerChanged(object sender, EventArgs args) { // Perform some logic here to update the view if(_selectedCustomer != args.Value) { _selectedCustomer = args.Value; _managementView.DisplayCustomer(_selectedCustomer); } } } 

Dans le présentateur, nous pouvons utiliser un autre modèle de conception appelé dependency injection pour fournir un access à notre vue et à toutes les classes de modèle dont nous pourrions avoir besoin. Dans cet exemple, j’ai un CustomerRepository qui est chargé de récupérer les détails du client.

Dans le constructeur, nous avons deux lignes de code importantes. Premièrement, nous avons souscrit à l’événement SelectedCustomerChanged de notre sharepoint vue, c’est ici que nous pouvons effectuer des actions associées. Deuxièmement, nous avons appelé InitilaizeCustomers avec des données du référentiel.

Pour l’instant, nous n’avons pas encore défini d’implémentation concrète. Tout ce que nous avons à faire est de créer un object qui implémente ICustomerManagementView . Par exemple, dans une application Windows Forms, nous pouvons effectuer les opérations suivantes:

 public partial class CustomerManagementView : Form, ICustomerManagementView { public CustomerManagementView() { this.InitializeComponents(); } public void InitializeCustomers(ICustomer[] customers) { // Populate the tree view with customer details } public void DisplayCustomer(ICustomer customer) { // Display the customer... } // Event handler that responds to node selection private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e) { var customer = e.Node.Tag as ICustomer; if(customer != null) { this.OnSelectedCustomerChanged(new EventArgs(customer)); } } // Protected method so that we can raise our event protected virtual void OnSelectedCustomerChanged(EventArgs args) { var eventHandler = this.SelectedCustomerChanged; if(eventHandler != null) { eventHandler.Invoke(this, args); } } // Our view will raise an event each time the selected customer changes public event EventHandler> SelectedCustomerChanged; } 

Si nous voulions tester notre logique de présentation, nous pourrions nous moquer de notre sharepoint vue et effectuer certaines affirmations.

EDIT: arguments d’événement personnalisés inclus

 public class EventArgs : EventArgs { private readonly T _value; public EventArgs(T value) { _value = value; } public T Value { get { return _value; } } } 

Je les diviserais en vues séparées avec leurs propres cadeaux et utiliserais un présentateur / une vue “contrôlant” pour gérer la délégation de messages entre eux. Cela facilitera non seulement la testabilité, mais permettra également à vos contrôles de continuer à remplir leur SRP.

Donc, dans votre cas, vous pourriez avoir un IFormManager que votre fenêtre principale implémentera, puis un IFileManager, ILoggerWindow, etc.

Bien que cela puisse être un peu excessif à utiliser, je vous suggère de jeter un coup d’œil à Smart Client Software Factory (de l’équipe Microsoft Patterns and Practices). Est-ce que ce genre de composition de vues est assez bien, donc peut-être que vous pourriez avoir de bonnes idées.