147 votes

Bons exemples de modèle MVVM

Je travaille actuellement avec le modèle Microsoft MVVM et je trouve le manque d'exemples détaillés frustrant. L'exemple inclus du ContactBook montre très peu de gestion des commandes et le seul autre exemple que j'ai trouvé est issu d'un article du magazine MSDN où les concepts sont similaires mais utilisent une approche légèrement différente et manquent toujours de complexité. Existe-t-il des exemples décents de MVVM qui montrent au moins des opérations CRUD de base et des commutations de dialogues/contenus?


Les suggestions de tout le monde ont été vraiment utiles et je vais commencer à compiler une liste de bonnes ressources

Frameworks/Modèles

Articles Utiles

Vidéos

Librairies Supplémentaires

0 votes

Je suis content que ces ressources aient aidé. Je suis actuellement sur ma deuxième application MVVM en production et continuerai à ajouter du contenu qui sera utile pour ceux qui débutent dès que je le trouverai.

60voto

Egor Points 1318

Il n'est malheureusement pas un grand MVVM exemple d'application qui fait tout, et il ya beaucoup d'approches différentes de faire les choses. Tout d'abord, vous voudrez peut-être obtenir familier avec celui de l'application des cadres (Prism est un choix décent), parce qu'ils vous fournissent des outils pratiques comme l'injection de dépendance, commandant, agrégation d'événements, etc facilement essayer différents modèles qui vous conviennent.

Le prisme de presse:
http://www.codeplex.com/CompositeWPF

Il comprend un bon exemple d'application (stock trader) avec un lot de petits exemples et comment. Au moins c'est une bonne démonstration de plusieurs sous-modèles que les gens utilisent pour faire MVVM fonctionnent réellement. Ils ont des exemples pour les deux CRUD et les boîtes de dialogue, je crois.

Prism n'est pas nécessairement pour chaque projet, mais c'est une bonne chose pour se familiariser avec.

CRUD: Cette partie est assez facile, WPF deux façon de liaisons de le rendre vraiment facile pour modifier la plupart des données. Le vrai truc est de fournir un modèle qui le rend facile à mettre en place l'INTERFACE utilisateur. À tout le moins, vous voulez vous assurer que votre ViewModel (ou business object) implémente INotifyPropertyChanged pour prendre en charge la liaison et vous pouvez lier les propriétés directement à des contrôles d'INTERFACE utilisateur, mais vous pouvez aussi mettre en oeuvre IDataErrorInfo pour la validation. En règle générale, si vous utilisez une sorte de solution ORM configuration de CRUD est un composant logiciel enfichable.

Cet article montre simples opérations crud: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

Il est construit sur LinqToSql, mais c'est sans importance pour l'exemple - tout ce qui est important, c'est que votre entreprise objets de mettre en oeuvre INotifyPropertyChanged (dont les classes générées par LinqToSql faire). MVVM n'est pas le point de cet exemple, mais je ne pense pas que c'est important dans ce cas.

Cet article montre la validation des données
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

Encore une fois, la plupart des ORM solutions de générer des classes qui implémentent déjà IDataErrorInfo et généralement fournir un mécanisme pour le faire, il est facile d'ajouter des règles de validation.

La plupart du temps, vous pouvez prendre un objet(modèle) créé par un ORM et l'envelopper dans un ViewModel qu'il détient et des commandes pour enregistrer/effacer - et vous êtes prêt à lier l'INTERFACE utilisateur directement les propriétés du modèle.

Le point de vue de ressembler à quelque chose comme ceci (ViewModel a une propriété Item qui détient le modèle, comme une classe créée dans le ORM):

<StackPanel>
   <StackPanel DataContext=Item>
      <TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
      <TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
   </StackPanel>
   <Button Command="{Binding SaveCommand}" />
   <Button Command="{Binding CancelCommand}" />
</StackPanel>

Boîtes de dialogue: Les boîtes de dialogue et MVVM sont un peu délicat. Je préfère utiliser une saveur du Médiateur approche avec les boîtes de dialogue, vous pouvez lire un peu plus à ce sujet dans ce StackOverflow question:
WPF MVVM exemple de boîte de dialogue

Mon approche habituelle, ce qui n'est pas tout à fait classique MVVM, peuvent être résumées comme suit:

Une classe de base pour un dialogue ViewModel qui expose les commandes pour valider et annuler des actions, un événement permet à la vue de savoir qu'un dialogue est prêt à être fermé, et tout le reste vous aurez besoin de toutes vos boîtes de dialogue.

Une vue générique pour votre boîte de dialogue, ce qui peut être une fenêtre, ou une coutume "modal" superposition de contrôle de type. En son cœur, c'est un présentateur qui nous décharge de ce dernier, et il gère le câblage pour la fermeture de la fenêtre (par exemple sur des données de changement de contexte, vous pouvez vérifier si la nouvelle ViewModel est hérité de votre classe de base, et si elle l'est, abonnez-vous à la proximité de l'événement (le gestionnaire d'affecter la boîte de dialogue résultat). Si vous fournissent une solution universelle à proximité de la fonctionnalité (le bouton X, par exemple), vous devriez assurez-vous d'exécuter pertinentes de la commande fermer dans le ViewModel.

Quelque part vous avez besoin de fournir des modèles de données pour votre Viewmodel, ils peuvent être très simple, en particulier depuis, vous avez probablement une vue pour chaque boîte de dialogue encapsulé dans une commande distincte. Le modèle de données par défaut pour un ViewModel serait alors ressembler à ceci:

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}>
   <views:AddressEditView DataContext={Binding} />
</DataTemplate>

La boîte de dialogue vue doit avoir accès à ceux-ci, parce que sinon ça ne savez pas comment montrer le ViewModel, de côté par le partage de l'INTERFACE de dialogue de son contenu sont essentiellement ceci:

<ContentControl Content={Binding} />

L'implicite de données de modèle de carte de la vue du modèle, mais qui se lance?

Ce n'est pas si mvvm partie. Une façon de le faire est d'utiliser un événement mondial. Ce que je pense, c'est une meilleure chose à faire est d'utiliser un agrégateur d'événements type d'installation, fournis par le biais de l'injection de dépendances - de cette façon, l'événement est mondial à un conteneur, pas l'ensemble de l'application. Prism utilise l'unité cadre de contenants, de la sémantique et de l'injection de dépendance, et dans l'ensemble j'aime l'Unité tout à fait un peu.

Habituellement, il a un sens de la racine de la fenêtre pour vous abonner à cette manifestation, il peut ouvrir la boîte de dialogue et l'ensemble de ses données de contexte pour le ViewModel qui est transmis avec une élévation de l'événement.

Cette mise en place de cette manière permet de ViewModels demander l'application pour ouvrir un dialogue et de répondre aux actions de l'utilisateur sans rien connaître de l'INTERFACE utilisateur, donc, pour la plupart, le MVVM-ness reste complet.

Il ya des moments, cependant, où l'INTERFACE est de soulever les boîtes de dialogue, ce qui peut rendre les choses un peu plus compliqué. Considérez par exemple, si la boîte de dialogue position dépend de l'emplacement du bouton qui s'ouvre. Dans ce cas, vous devez avoir une INTERFACE utilisateur spécifique info lorsque vous demander une boîte de dialogue ouvrir. J'ai en général de créer une catégorie distincte qui est titulaire d'un ViewModel et de l'INTERFACE utilisateur informations. Malheureusement, certains de couplage semble inévitable.

Le Pseudo-code d'un gestionnaire de bouton qui déclenche une boîte de dialogue dans laquelle les besoins de la position de l'élément de données:

ButtonClickHandler(sender, args){
    var vm = DataContext as ISomeDialogProvider; // check for null
    var ui_vm = new ViewModelContainer();
    // assign margin, width, or anything else that your custom dialog might require
    ...
    ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
    // raise the dialog show event
}

La boîte de dialogue vue de les lier à des données de position, et de transmettre le contenu de l'ViewModel à l'intérieur de la ContentControl. Le ViewModel lui-même ne sait rien à propos de l'INTERFACE utilisateur.

En général, je n'utilise pas l' DialogResult retour de la propriété de l' ShowDialog() méthode ou attendre le fil à bloc jusqu'à ce que la boîte de dialogue est fermée. Un non-standard de la boîte de dialogue modale ne fonctionne pas toujours comme ça, et dans un environnement de composite souvent, vous n'avez pas vraiment envie d'un gestionnaire d'événements pour bloquer comme ça de toute façon. Je préfère laisser le Viewmodel traiter avec cela, le créateur d'un ViewModel peut s'abonner à ses événements pertinents, définir s'engager/d'annuler les méthodes, etc, donc il n'est pas nécessaire de s'appuyer sur ce mécanisme d'INTERFACE utilisateur.

Ainsi, au lieu de ce flux:

// in code behind
var result = somedialog.ShowDialog();
if (result == ...

J'utilise:

// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit 
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container

Je préfère de cette façon parce que la plupart de mes boîtes de dialogue sont non-bloquant pseudo-modale des contrôles et de le faire de cette façon semble plus simple que de travailler autour d'elle. Facile de test de l'unité.

0 votes

Merci pour la réponse détaillée! J'ai récemment découvert que mon plus gros problème est lorsque j'ai besoin d'avoir un MainViewModel communiquer avec d'autres view models pour gérer le flux de l'application. Cependant, il semble que MVVM + Mediator soit l'approche populaire.

2 votes

Le Médiateur aide vraiment, le modèle de l'agrégateur d'événements (Prism a une bonne implémentation) est également très utile lorsque le faible couplage est un objectif. De plus, votre vue modèle principale a généralement ses propres modèles de vue enfants et ne devrait pas avoir de problèmes pour communiquer avec eux. Vous devez utiliser un médiateur et/ou un agrégateur d'événements lorsque vos modèles de vue enfants ont besoin d'interagir avec d'autres modules de votre application qu'ils ne connaissent pas nécessairement - y compris l'interface utilisateur (mon exemple de dialogue concerne ce cas particulier).

1 votes

Les directives pour travailler avec des dialogues et des fenêtres ont été vraiment utiles. Cependant, je suis bloqué avec quelques problèmes: 1. Comment définir le titre de la fenêtre depuis la vue? 2. Comment gérer le réglage de la fenêtre propriétaire?

6voto

nportelli Points 2350

Jason Dolinger a fait un bon screencast de MVVM. Comme l'a mentionné Egor, il n'y a pas un bon exemple unique. Ils sont partout. La plupart sont de bons exemples de MVVM, mais pas lorsque vous abordez des problèmes complexes. Chacun a sa propre manière de faire. Laurent Bugnion a également une bonne manière de communiquer entre les viewmodels. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch est aussi un bon exemple. Paul Stovel a un bon article qui explique beaucoup avec son framework Magellan.

3voto

Andy S Points 3975

Avez-vous regardé Caliburn? L'exemple de ContactManager contient beaucoup de bonnes choses. Les exemples génériques de WPF donnent également un bon aperçu des commandes. La documentation est assez bonne et les forums sont actifs. Recommandé!

2voto

Reed Copsey Points 315315

Le projet exemple dans le framework Cinch montre des outils basiques de CRUD et de navigation. C'est un assez bon exemple d'utilisation de MVVM, et inclut un article en plusieurs parties expliquant son utilisation et ses motivations.

2voto

Scott Whitlock Points 8172

J'ai également partagé votre frustration. Je suis en train de développer une application et j'avais ces 3 exigences :

  • Extensible
  • WPF avec MVVM
  • Exemples compatibles avec la GPL

Tout ce que j'ai trouvé était fragmenté, donc j'ai simplement commencé à l'écrire du mieux que je pouvais. Après m'être un peu investi, j'ai réalisé qu'il pourrait y avoir d'autres personnes (comme vous) qui pourraient avoir besoin d'une référence d'application, donc j'ai refactorisé les éléments génériques en un framework d'application WPF/MVVM que j'ai publié sous la LGPL. Je l'ai nommé SoapBox Core. Si vous allez sur la page de téléchargement, vous verrez qu'elle comprend une petite application de démonstration, et le code source de cette application de démonstration est également disponible en téléchargement.

EDIT : J'ai également publié un article CodeProject expliquant son fonctionnement.

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