Отменить внутри WPF M-V-VM, как это подходит? - PullRequest
12 голосов
/ 23 мая 2009

В моих предыдущих проектах я уже реализовал систему отмены в c ++, и я знаю, как она работает. Мне также известен шаблон Command.

Я буду реализовывать настольное приложение C # / WPF и хотел бы основывать свой дизайн на шаблоне M-V-VM.

Приложение будет:

  • будет относительно небольшим проектом (2-3 недели по оценкам работы на 1 разработчика)
  • имеют простую модель данных с постоянством (linq to XML)
  • поддержка отмены / повтора

Мне было интересно, есть ли у кого-нибудь опыт внедрения системы отмены при следовании шаблону M-V-VM. Как это вписалось бы в это? Какую выгоду он может извлечь из уведомлений INotifyPropertyChanged и INotifyCollectionChanged, поэтому при реализации моделей (бизнес-объектов) требуется минимальная работа.

Я бы подумал, что система отмены каким-то образом интегрируется в слой ViewModel, поскольку это состояние пользовательского интерфейса.

Есть мысли?

Ответы [ 3 ]

13 голосов
/ 22 октября 2009

Вот решение, которое я использовал для своего проекта. Решение оказалось отлично работает.

Система использует объекты событий отмены, где каждое событие отмены знает, как отменить и повторить себя.

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

Мне удалось построить систему, реализовав только 2 события отмены: одно для изменения свойств; один для изменений коллекции.

Идея состоит в том, что эти события реализуют Undo / Redo путем непосредственного изменения модели.

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 позаботится о создании событий отмены путем вызова функций 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); }
    }
}

Наконец, есть UndoManager (синглтон проекта), в котором хранится стек отмены и стек восстановления.

4 голосов
/ 21 июня 2011

Может оказаться полезной среда Monitored Undo Framework. http://muf.codeplex.com/. Он не использует шаблон команды «сверху вниз», но вместо этого следит за изменениями по мере их возникновения и позволяет поместить делегата в стек отмены, который отменит изменение.

Я создал это как часть приложения WPF, созданного с использованием MVVM. Большая часть действий по отмене произошла в нашей базовой доменной модели, но мы также подключились к некоторым областям ViewModels, чтобы разрешить отмену / повтор там тоже.

Более подробную информацию и документацию можно найти на сайте codeplex по адресу http://muf.codeplex.com/.

.
2 голосов
/ 25 мая 2009

Полагаю, вы связываете шаблон Команды с Memento?

Я думаю, что система отмены каким-то образом интегрируется в слой ViewModel, так как это состояние пользовательского интерфейса.

?! Обычно отмена / повтор действует на бизнес-объектах, а пользовательский интерфейс отражает бизнес-уровень.

Скажем, у нас есть класс продукта со строкой "Description". ProductVM предоставляет строковое свойство, которое вызывает PropertyChanged. На модификации память хранит экземпляр старой модели. Если вы отменили, восстановите сувенир, используя ProductVM.Description = (сувенир как продукт). Описание: модель будет обновлена ​​и пользовательский интерфейс тоже.

Примечание: избегайте (сувенир как продукт) , только для образца;)

...