2009-05-22 11 views
11

Nei miei progetti precedenti, ho già implementato il sistema di annullamento in C++ e so come funziona. Sono anche a conoscenza del modello di comando.Annulla all'interno di WPF M-V-VM, come si adatta?

Implementerò un'applicazione desktop C#/WPF e vorrei basare il mio disegno sul modello M-V-VM.

l'applicazione sarà:

  • essere relativamente un piccolo progetto (2-3 settimane di lavoro stimato per 1 dev)
  • hanno un modello di dati semplice, con la persistenza (LINQ to XML)
  • supporto undo/redo

Mi chiedevo se qualcuno ha esperienza con l'implementazione di un sistema di annullamento quando si segue il modello MV-VM. Come si adatterebbe in esso? Come può trarre beneficio dalle notifiche INotifyPropertyChanged e INotifyCollectionChanged, quindi è necessario un lavoro minimo quando si implementano i Modelli (oggetti business).

Penso che il sistema di annullamento possa essere integrato nel livello ViewModel, in quanto è uno stato dell'interfaccia utente.

Qualche idea?

risposta

12

Ecco la soluzione che ho usato per il mio progetto. La soluzione ha dimostrato di funzionare perfettamente.

Il sistema utilizza gli oggetti evento di annullamento, in cui ogni evento di annullamento sa come annullare e ripristinare se stesso.

interface IUndoEvent 
{ 
    void Undo(); 
    void Redo(); 
} 

Sono riuscito a creare il sistema implementando solo 2 eventi di annullamento: uno per le modifiche delle proprietà; uno per le modifiche alla collezione.

L'idea è che quegli eventi implementino l'annullamento/ripristino modificando direttamente il modello.

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) 
    } 
} 

Il ViewModel prendersi cura della creazione di annullare eventi chiamando funzioni 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); } 
    } 
} 

Infine, c'è un UndoManager (progetto Singleton) che memorizza lo stack di annullamento e lo stack Redo.

1

Suppongo che tu stia accoppiando il modello di comando con un Memento?

Penso che il sistema di annullamento sarebbe integrato nel livello ViewModel, in quanto è uno stato dell'interfaccia utente.

?! Di solito, annulla/ripristina agisce sugli oggetti business e l'interfaccia utente riflette il livello aziendale.

Supponiamo di avere una classe di prodotto con una stringa "Descrizione". Il ProductVM espone una proprietà stringa che solleva PropertyChanged. In modifica, il memento mantiene la vecchia istanza del modello. Se annulli, ripristina il memento utilizzando ProductVM.Description = (memento come prodotto) .Descrizione: il modello verrà aggiornato e anche l'interfaccia utente.

NB: evitare il (ricordo come prodotto), solo per il campione;)

3

È possibile che il quadro di annullamento monitorato sia utile. http://muf.codeplex.com/. Non utilizza il modello di comando "top down", ma monitora le modifiche mentre si verificano e consente di inserire un delegato nello stack di annullamento che annullerà la modifica.

L'ho creato come parte di un'applicazione WPF creata con MVVM. La maggior parte delle azioni di annullamento ha avuto origine nel nostro modello di dominio sottostante, ma ci siamo anche agganciati in alcune aree di ViewModels per consentire anche l'annullamento/ripetizione.

È possibile trovare ulteriori informazioni e documentazione sul sito di codeplex allo http://muf.codeplex.com/.