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é.