Не могу разобраться с реализацией функций Undo / Redo, стоит ли мне использовать Stack? - PullRequest
2 голосов
/ 28 июля 2011

Я сейчас немного сбит с толку, думаю, в один из дней.

Мне нужно реализовать функциональность Undo и Redo для формы.Для простоты, скажем, я сохраняю только тот элемент управления, который был изменен, и значение, которое он имел, когда покинул Focus.

Как мне сохранить эту информацию таким образом, чтобы я мог вернуться назад или вперед в 'timeline '.

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

Код нужен, не совсем, но это поможет.Меня больше интересует алгоритм, который мне нужно реализовать.Есть предложения?

Ответы [ 4 ]

4 голосов
/ 28 июля 2011

Да, вы бы использовали стек.Есть несколько способов сделать это;Прочитайте эти ссылки:

http://en.wikipedia.org/wiki/Command_pattern

http://en.wikipedia.org/wiki/Memento_pattern

У каждого есть свои плюсы / минусы.

4 голосов
/ 28 июля 2011

Я бы использовал интерфейс IUndoableAction. Реализации могут хранить любые данные, которые им нужно было сделать и отменить. Тогда да, я бы использовал стек для их удержания.

interface IUndoableAction
{
    void Do();
    void Undo();
}
Stack<IUndoableAction> Actions;

Каждый вид действия будет реализовывать методы Do и Undo.

Тогда где-то были бы эти два метода:

    void PerformAction(IUndoableActionaction)
    {
        Actions.Push(action);
        action.Do();
    }

    void Undo()
    {
        var action = Actions.Pop();
        action.Undo();
    }

Что касается того, что хранить в классах действий, некоторые действия могут просто хранить старое значение. Тем не менее, однажды у меня было действие, чтобы поменять две строки в электронной таблице. Я не сохранял значения каждой ячейки в обеих строках - я просто сохранял индексы строк, чтобы их можно было вернуть обратно. Может быть легко заполнить тонны памяти, если вы сохраняете все это состояние для каждого действия.

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

4 голосов
/ 28 июля 2011

Стек идеально подходит, если вы нажимаете «изменение» на него, а когда отменяете, вынимаете «изменение» из него.Затем вы помещаете это измененное изменение в другой стек, представляющий повтор.В какой-то момент в будущем, мы надеемся, что при сохранении вы очистите оба стека.

Это на самом деле не так просто, как вам нужно записать тип изменения, понять старые и новые значения и т. Д.Поэтому, когда вы извлекаете из стека отмены, всплывающее окно должно описывать, каким было предыдущее значение и каким элементом управления оно было установлено.

Инверсия для стека повторения, оно должно понимать, какое новое значение былои куда это делось.Но да, идея двух стеков - это хорошее начало для отмены повторов в домашнем пиве.

Хороший пример отмены на основе бизнес-объектов - CSLA.NET, которая имеет UndoableBase:

http://www.lhotka.net/cslanet/

http://www.koders.com/csharp/fidCF6AB2CF035B830FF6E40AA22C8AE7B135BE1FC0.aspx?s=serializationinfo

Однако здесь записывается снимок состояния объекта, поэтому он будет более продвинутым, чем ваша концепция на основе форм.Тем не менее, CSLA.NET предлагает полную поддержку связывания данных, поэтому объект, связанный с данными, наследуемый от UndoableBase, естественно будет поддерживать отмену (не повтор) в пользовательском интерфейсе.

0 голосов
/ 28 июля 2011

Вероятно, самое простое - иметь комбинацию стеков отмены и повторения.

Альтернативой является наличие массива или списка действий и просто увеличение / уменьшение указателя на индекс в массиве. Когда действие отменено, индекс перемещается назад на единицу, а когда действие повторяется, индекс перемещается вперед на единицу. Преимущество здесь состоит в том, что вам не требуется последовательность действий для каждого действия.

Что нужно учитывать:

  • Если вы отмените несколько раз, а затем выполните действие, все повторные действия должны быть исключены.
  • Убедитесь, что вы проверили границы и убедитесь, что есть действие, которое можно отменить / повторить, прежде чем пытаться выполнить отмену / повтор.
...