Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undo inside WPF M-V-VM, how does it fit?

Tags:

undo

c#

mvvm

wpf

In my previous projects, I have already implemented undo system in c++, and I know how it work. I am also aware of the Command pattern.

I will be implementing a C#/WPF desktop application and would like to base my design on the M-V-VM pattern.

The application will:

  • be relatively a small project (2-3 weeks estimated work for 1 dev)
  • have a simple data model with persistence (linq to XML)
  • support undo/redo

I was wondering if anybody has experience with implementing an undo system when following the M-V-VM pattern. How would it fit in it? How can it benefit from the INotifyPropertyChanged and INotifyCollectionChanged notifications so minimal work is required when implementing the Models (business objects).

I would think the undo system would some kind of integrated into the ViewModel layer, as it is a UI state.

Any thought?

like image 622
decasteljau Avatar asked May 22 '09 20:05

decasteljau


1 Answers

Here is the solution I used for my project. The solution proved to be working perfectly.

The system is using undo event objects, where each undo event know how to undo and redo itself.

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

I was able to build the system by implementing only 2 undo events: One for property changes; one for collection changes.

The idea is that those events implement the Undo/Redo by modifying the model directly.

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

The ViewModel take care of creating undo events by calling ViewModelBase functions:

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

Finally, there is a UndoManager (project singleton) that stores the undo stack and the redo stack.

like image 83
decasteljau Avatar answered Oct 03 '22 01:10

decasteljau