2014-09-08 1 views
0

Я не могу заставить Undo и Redo правильно вести себя при использовании диалога.Как реализовать диалог изменения состояния с поддержкой отмены/повтора в Catel?

У меня есть простая модель со свойствами, указывающими состояние объекта (running, paused, stopped), которые могут быть изменены с помощью диалогового окна. Случается, что я получаю действия, которые, кажется, ничего не делают в моей очереди отмены или отменят, возвращают объект в промежуточное состояние.

Объект модели зарегистрирован в memento в конструкторе. В диалоговом окне есть три переключателя, каждый из которых представляет одно из трех разных состояний. Каждый переключатель используется для каждой команды. Каждая команда выполняет изменение свойства. Я пробовал два разных подхода, либо каждая команда устанавливает свойство непосредственно в объекте, либо каждая команда устанавливает переменную экземпляра для модели представления при вызове, а затем я использую событие Saving для изменения объекта.

Если вы используете первый подход, каждое изменение свойств помещается в очередь Undo, если пользователь нажимает больше, чем один радиообъект, прежде чем нажимать Ok в диалоговом окне. Пытался решить это, обернув весь диалог в пакет, но это приведет к отмене изменения состояния, объект возвращается в состояние, которое оно имело до окончательного, т. Е. Если для свойства было установлено значение stopped перед открытием диалогового окна и нажатие кнопки затем запустите одно и, наконец, Ok, undo установит свойство на paused вместо ожидаемого stopped.

Если вы используете второй подход, пользователь открывает диалоговое окно, измените его на paused, нажмите «ОК» в диалоговом окне «Отменить/повторить», как и следовало ожидать, но если диалог снова откроется, а «Отмена» будет добавлено еще одно действие очередь Undo, то есть пользователь должен дважды нажать «Отменить», чтобы вернуться к исходному состоянию stopped.

Итак, мой вопрос заключается в том, как это должно быть правильно реализовано для получения ожидаемого поведения; что каждое диалоговое взаимодействие можно отменить, а не каждое взаимодействие в диалоговом окне?

Вот код для ViewModel:

namespace UndoRedoTest.ViewModels 
{ 
    using Catel.Data; 
    using Catel.MVVM; 
    public class StartStopViewModel : ViewModelBase 
    { 
     Machine.MachineState _state; 
     public StartStopViewModel(Machine controlledMachine) 
     { 
      ControlledMachine = controlledMachine; 
      _state = controlledMachine.State; 
      StartMachine = new Command(OnStartMachineExecute); 
      PauseMachine = new Command(OnPauseMachineExecute); 
      StopMachine = new Command(OnStopMachineExecute); 
      Saving += StartStopViewModel_Saving; 
     } 

     void StartStopViewModel_Saving(object sender, SavingEventArgs e) 
     { 
      ControlledMachine.State = _state; 
     } 

     [Model] 
     public Machine ControlledMachine 
     { 
      get { return GetValue<Machine>(ControlledMachineProperty); } 
      private set { SetValue(ControlledMachineProperty, value); } 
     } 

     public static readonly PropertyData ControlledMachineProperty = RegisterProperty("ControlledMachine", typeof(Machine)); 

     public override string Title { get { return "Set Machine state"; } } 

     public Command StartMachine { get; private set; } 
     public Command PauseMachine { get; private set; } 
     public Command StopMachine { get; private set; } 

     private void OnStartMachineExecute() 
     { 
      _state = Machine.MachineState.RUNNING; 
      //ControlledMachine.SecondState = Machine.MachineState.RUNNING; 
     } 

     private void OnPauseMachineExecute() 
     { 
      _state = Machine.MachineState.PAUSED; 
      //ControlledMachine.SecondState = Machine.MachineState.PAUSED; 
     } 

     private void OnStopMachineExecute() 
     { 
      _state = Machine.MachineState.STOPPED; 
      //ControlledMachine.SecondState = Machine.MachineState.STOPPED; 
     } 
    } 
} 

ответ

1

Прежде всего, не подписаться на событие Сохранение а просто переопределить метод Save(). Обратите внимание, что Catel обрабатывает модельное состояние для вас, когда вы украшаете модель с помощью ModelAttribute. Поэтому вам нужно получить предварительное и постсоветское диалоговое окно, а затем нажать набор результатов в пакет.

Например, я хотел бы создать методы расширения для класса объектов (или класс модели), как это:

public static Dictionary<string, object> GetProperties(this IModel model) 
{ 
    // todo: return properties 
} 

Тогда вы сделаете это в Initialize и Сохранить метод и вы бы имеют 2 набора свойств (состояние предварительного и пост-состояния). Теперь у вас есть, что это легко вычислить разницу:

public static Dictionary<string, object> GetChangedProperties(Dictionary<string, object> preState, Dictionary<string, object> postState) 
{ 
    // todo: calculate difference 
} 

Теперь у вас есть разница, вы можете создать Memento партию, и было бы восстановить точное состояние, как вы ожидали.

пс.было бы здорово, если бы вы могли поместить это в сообщение в блоге после его создания или создать PR с этой функцией.

+0

Я не понимаю, почему я должен делать это таким образом и почему это не работает так, как я его реализовал , Во всяком случае, я заставил его вести себя так, как ожидалось, исходя из информации выше. Я создал копию свойств, когда диалог создается как начальное состояние. Затем в методе «Сохранить» я перехожу через словарь свойств, который ищет тот, который изменил этот диалог, и посмотрел, изменилось ли оно. Если он изменился, я создаю ActionUndo и добавляю его в пакет. Наконец, я добавляю пакет в службу Memento. Уверен, могу написать сообщение об этом. Но что такое PR? –

+0

PR - запрос Pull –

+0

aah, вы имеете в виду интегрировать его в ModelBase и ViewModelBase. Думаю, мне нужно было бы лучше понять Catel, но может попробовать, и если вам это нравится, примите это. –