2009-05-22 9 views
11

Dans mes projets précédents, j'ai déjà implémenté le système d'annulation en C++, et je sais comment cela fonctionne. Je suis également conscient du modèle de commande.Annuler dans WPF M-V-VM, comment ça va?

je vais implantera une application de bureau C#/WPF et voudrait fonder ma conception sur le modèle M-V-VM.

L'application:

  • relativement un petit projet (2-3 semaines de travail estimé pour 1 dev)
  • ont un modèle de données simple avec persistance (LINQ to XML)
  • support undo/redo

Je me demandais si quelqu'un avait de l'expérience avec l'implémentation d'un système d'annulation en suivant le modèle MV-VM. Comment cela rentrerait-il? Comment peut-il bénéficier des notifications INotifyPropertyChanged et INotifyCollectionChanged, de sorte qu'un travail minimal est requis lors de l'implémentation des modèles (objets métier).

Je pense le système undo serait une sorte d'intégrer dans la couche ViewModel, comme il est un état de l'interface utilisateur.

Une idée?

Répondre

12

Voici la solution je pour mon projet. La solution s'est avérée fonctionner parfaitement.

Le système utilise des objets d'événement d'annulation, où chaque événement d'annulation sait comment annuler et refaire lui-même. J'ai pu construire le système en implémentant seulement 2 événements d'annulation: Un pour les changements de propriétés; un pour les changements de collection.

L'idée est que ces événements implémentent l'annulation/rétablissement en modifiant directement le modèle.

class PropertyChangeUndoEvent : IUndoEvent 
{ 
    private ModelBase _target; 
    private string _propertyName; 
    private object _oldValue; 
    private object _newValue; 

    public PropertyChangeUndoEvent(ModelBase target, string propertyName, object oldValue, object newValue) 
    { 
     _target = target; 
     _propertyName = propertyName; 
     _oldValue = oldValue; 
     _newValue = newValue; 
    } 

    public void Undo() 
    { 
     SetValue(_oldValue); 
    } 

    public void Redo() 
    { 
     SetValue(_newValue); 
    } 

    private void SetValue(object value) 
    { 
     // Set Value on the _target using reflection (_propertyName) 
    } 
} 

ViewModel prendre soin de créer annuler des événements en appelant des fonctions ViewModelBase:

class MyViewModel : ViewModelBase 
{ 
    public string Name 
    { 
     get { return _model.Name; } 

     // The SetValue will create a undo event, and push it to the UndoManager 
     set { SetValue(_model, "Name", value); } 
    } 
} 

Enfin, il y a un UndoManager (projet singleton) qui stocke la pile d'annulation et la pile de rétablissement.

1

Je suppose que vous associez le motif de commande à un Memento?

Je pense que le système d'annulation serait en quelque sorte intégré dans la couche ViewModel, car il s'agit d'un état de l'interface utilisateur.

?! Généralement, annuler/rétablir agit sur les objets métier et l'interface utilisateur reflète la couche de gestion.

Disons que nous avons une classe de produit avec une chaîne « Description ». ProductVM expose une propriété de chaîne qui déclenche PropertyChanged. En cas de modification, le memento conserve l'ancienne instance de modèle. Si vous annulez, restaurez le mémento à l'aide de ProductVM.Description = (memento as Product) .Description: le modèle sera mis à jour et l'interface utilisateur aussi.

NB: éviter le (memento comme produit), juste pour l'échantillon;)

3

Vous pouvez trouver le cadre d'annulation surveillé utile. http://muf.codeplex.com/. Il n'utilise pas le modèle de commande "top down", mais surveille plutôt les changements au fur et à mesure qu'ils se produisent et vous permet de placer un délégué sur la pile d'annulation qui inversera le changement. J'ai créé ceci dans le cadre d'une application WPF qui a été créée à l'aide de MVVM. La plupart des actions d'annulation provenaient de notre modèle de domaine sous-jacent, mais nous avons également accroché dans certaines zones des ViewModels pour permettre d'annuler/refaire là aussi.

Vous trouverez plus d'informations et de documentation sur le site codeplex au http://muf.codeplex.com/.

Questions connexes