Отмените Redo в WPF / C # в уже работающем приложении - PullRequest
4 голосов
/ 02 декабря 2010

Я уже провел некоторое исследование относительно того, как я могу достичь названия этого вопроса.Приложение, над которым я работаю, разрабатывалось пару лет или около того (хотя медленный прогресс, вы все знаете, как это происходит в реальном мире).Теперь я должен добавить в Undo / Redo многоуровневую функциональность.Немного поздно сказать «ты должен был подумать об этом, прежде чем начать» ... ну, мы действительно думали об этом - и мы ничего не делали с этим, и вот оно.Из поиска по SO (и внешним ссылкам) я вижу, что два наиболее распространенных метода выглядят так: *

Шаблон команды

Шаблон Memento

Шаблон команды выглядит так, как будто это было бы чертовски много работы, я могу только представить, что в процессе он тоже выбрасывает тысячи ошибок, поэтому мне это не очень нравится.

Шаблон Memento на самом деле очень похож на то, что я имел в виду для этого.Я думал, что если бы был какой-то способ быстро сделать снимок объектной модели, находящейся в данный момент в памяти, я бы мог сохранить ее где-нибудь (возможно, также в памяти, может быть, в файле).Кажется, это отличная идея, единственная проблема, которую я вижу в этом, заключается в том, как она интегрируется с тем, что мы уже написали.Вы видите приложение в том виде, в котором оно есть у нас: оно рисует изображения на большой панели (возможно, сотнях), а затем позволяет пользователю манипулировать ими либо через пользовательский интерфейс, либо через пользовательскую сетку свойств.Все приложение связано с большим шаблоном наблюдателя.Второе что-то меняется, события запускаются, и все, что нужно обновить, делает.Это хорошо, но я не могу не думать, что если пользователь вводит текст в текстовое поле в сетке свойств, то перед тем, как пользовательский интерфейс будет задерживаться, будет небольшая задержка (кажется, что каждый раз, когда пользователь нажимает клавишу, будет добавлен новый снимок).в список отмены).Поэтому мой вопрос к вам ...

  • Знаете ли вы какие-либо хорошие альтернативы шаблону Memento, которые могут сработать.
  • Как вы думаете, шаблон Memento подойдет здесь?или это слишком сильно замедлит работу приложения.
  • Если шаблон Memento - это то, что нужно, то каков наиболее эффективный способ сделать снимок объектной модели (я думал, сериализацию или что-то в этом роде)
  • Должны ли снимки храниться в памяти или их можно поместить в файлы?

Если у вас все получилось, спасибо за чтение.Любой ваш вклад будет ценным и очень ценным.

Ответы [ 4 ]

5 голосов
/ 02 декабря 2010

Ну, вот моя мысль по этой проблеме.

1 - Вам нужна многоуровневая функция отмены / возврата.так что вам нужно хранить выполненные пользователем действия, которые можно хранить в стеке.

2- Ваша вторая проблема, как определить, что было изменено операцией, я думаю, через шаблон Memento, это довольно сложная задача.Memento - это все, что касается сохранения начального состояния объекта в вашей памяти.

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

Шаблон командыпредназначен для функциональности Undo / Redo, и я бы сказал, что это поздно, но стоит реализовать дизайн, который используется в течение нескольких лет и работает для большинства приложений.

3 голосов
/ 02 декабря 2010

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

Поскольку ваш граф объектов, вероятно, нетривиален (т. Е. Использует наследование, циклы, ...), интегрированные XmlSerializer и JsonSerializer исключены. Json.net поддерживает их, но делает некоторые преобразования с потерями для некоторых типов (локальные DateTimes, числа, ...), так что это тоже плохо.

Я думаю, что сериализаторам protobuf требуется либо некоторая форма DTD (файл .proto), либо оформление всех свойств с атрибутами, отображающими их имя в число, так что это может быть неоптимальным.

BinaryFormatter может сериализовать большинство вещей, вам просто нужно украсить все классы атрибутом [Serializable]. Но я не использовал его сам, поэтому могут быть подводные камни, о которых я не знаю. Возможно, связано с синглетонами или событиями.

1 голос
/ 21 июня 2011

Может оказаться полезной среда Monitored Undo Framework. http://muf.codeplex.com/

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

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

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

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

Дополнительную информацию и документацию можно найти на сайте codeplex по адресу http://muf.codeplex.com/. Библиотека также доступна через NuGet с поддержкой .NET 3.5, 4.0, SL4 и WP7.

1 голос
/ 02 декабря 2010

Для отмены / восстановления критически важны

  • знание того, какое состояние необходимо сохранить и восстановить
  • знание того, когда необходимо сохранить состояние

Добавление отмены / повторения после факта всегда является болезненным делом - (я знаю, что этот комментарий сейчас бесполезен для вас, но всегда лучше спроектировать поддержку в рамках приложения, прежде чем начать, так как он помогает людям использоватьнедопустимые шаблоны во время разработки).

Возможно, самый простой подход будет основан на использовании мемо:

  • Найдите все данные, которые составляют ваш "документ".Можете ли вы каким-то образом объединить эти данные, чтобы они образовали единое целое?Обычно, если вы можете сериализовать структуру вашего документа в файл, логика, которая вам нужна, заключается в системе сериализации, так что это дает вам выход. Недостатком использования этого напрямую является то, что вам обычно придется сериализовать все, чтобы отменитьбудет огромным и медленным.Если возможно, выполните рефакторинг кода таким образом, чтобы (а) имелся общий интерфейс сериализации, используемый во всем приложении (чтобы любая и каждая часть ваших данных могла быть сохранена / восстановлена ​​с помощью общего вызова), и (б) каждая подсистема инкапсулированатак что изменения данных должны проходить через общий интерфейс (вместо того, чтобы многие люди изменяли переменные-члены напрямую, все они должны вызывать API, предоставляемый объектом, чтобы запросить, чтобы он вносил изменения в себя) и (c) каждый подчиненный объект.часть данных хранит «номер версии».Каждый раз, когда производится изменение (через интерфейс в (b)), оно должно увеличивать этот номер версии.Этот подход означает, что теперь вы можете сканировать весь документ и использовать номера версий, чтобы найти только те его части, которые изменились с момента вашего последнего просмотра, а затем сериализовать минимальную сумму для сохранения и восстановления измененного состояния.

    • Предоставляет механизм, с помощью которого можно записать один шаг отмены.Это означает, что несколько систем могут вносить изменения в структуру данных, а затем, когда все будет обновлено, запускать запись отмены.Определить, когда это сделать, может быть непросто, но обычно это можно сделать, отсканировав документ на наличие изменений (см. Выше) в цикле сообщений, когда пользовательский интерфейс завершил обработку каждого входного события.

Кроме того, я бы посоветовал перейти на командный подход, поскольку у него есть много преимуществ, кроме отменить / повторить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...