![]() |
Модераторы: Partizan, gambit |
![]() ![]() ![]() |
|
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Необходимо реализовать команды Undo, Redo в графическом редакторе.
Существует несколько вариантов решения задачи: паттерны Command, Memento. Первый вариант мне больше нравится, потому что я так понимаю, что он более производительный, меньше занимает памяти, но в то же время, реализация является затруднительной, потому что многие действия не являются командами (к примеру, изменения положения и размеров элементов редактора), кроме того необходимо полностью самостоятельно определить логику команд. Потому решил использовать паттерн Memento. Но и в этом случае столкнулся с проблемами: 1. Нужно правильно определить когда следует и когда не следует сохранять состояние 2. Проблема производительности. При сохранении состояния, я сохраняю программу в формате XML (структуру определяю сам, использую LINQ, Xaml сериализация не может сохранить полностью состояние, ввиду ограниченности), при восстановлении - выполняется синтаксический разбор XML-документа (опять же использую LINQ). Если первая проблема не крититична, решаема, то вторая - более серьезная. Если в редакторе около 100 объектов, то десериализация занимает около 3.5 сек, что при выполнении комманды Undo слишком много. Есть какие-нить советы по поводу этого? У меня есть мысль, что можно в фоновом потоке выполнять десериализацию нескольких элементов стека, где хранятся состояния, но при этом возникнут другие проблемы, а если часто выполнять команду, то производительность может только ухудшиться. |
|||
|
||||
jonie |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 22 Всего: 118 |
Anyone, а что насчет сериализации НЕ в xml ?
-------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
|||
|
||||
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Да, пробывал бинарную, но не все внутренние классы моего контрола сериализуемые, потому сохранить его как целый объект не удалось, хотя появилась идея сериализировать не сам контрол, а создать свой класс, с полями наподобии моей структуры XML файла. Может и глупо, но должно быстрее работать. Забыл упомянуть что использую WPF. Это сообщение отредактировал(а) Anyone - 7.11.2009, 16:38 |
|||
|
||||
tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 63 Всего: 170 |
что-то я не все понял. Как паттерн Хранитель может заменить паттерн Команда? Что вообще между ними общего? Если хранитель - работает с состоянием, а команда - с поведением?
Да, конечно, историю комманд нужно хранить. Если она не помещается в память, то ее нужно хранить, используя паттерн Хранитель. Но в этом случае паттерн Хранитель выступает в роли дополнительного инструмента, но никак - не как альтернатива самой Команде. Допустим нам нужна возможность быстрого прохода по истории комманд... Но мы же не будем говорить, что паттерн Итератор тоже является альтернативой Комманде? ) Одним словом... я считаю что альтернативе паттерну Команда в данном случае нет. Что же касается механизма... То я бы не стал вообще хранить состояние ни в каком виде. Это избыточно. В конце концов нам не требуется восстанавливать всю графику с нуля при каждом Undo\Redo. А всего-лишь отменить\восстановить последнее действие. Поэтому хранить нужно параметры и имена комманд. Даже если нужно будет восстанавливать всю графику, сохраненную с предыдущей сессии, при старте новой сессии.... То, во первых, это не Undo\Redo будет... А во вторых - все равно рисование будет последовательным, т.е. это будет представлять собой последовательное выполнение восстановленных из хранилища комманд. В самом общем случае (без привязки к технологиям) : есть Представление, Модель и какой-угодно Контроллер. Как они связаны - не важно вообще. В результате действия пользователя Представление инициирует команду Контроллера, который работает с Моделью и отправляет результыты Представлению обратно. Каждая команда должна, кроме своих основных функций, иметь возможность отката всех произведенных ею действий. Она может хранить в себе параметры, которые ей были переданы. И на основе них производить свой откат. Список комманд хранится в хранилище комманд (с которым, кстати, может работать как раз Хранитель). У контроллера также есть комманды Undo\Redo, которые просто перемещают указатель комманд хранилища (назначают текущей новую команду) и вызывают: - или эту новую текущую команду Контроллера - или откат прежней команды (которая была текущей до моменты вызова Undo) Т.е. все отличие только в том, что команды Контроллера использует не Представление, а сам Контроллер (поскольку Представление может формировать только текущие параметры для комманд, но уж никак не для Redo или Undo) Это сообщение отредактировал(а) tol05 - 7.11.2009, 20:29 -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Я сохраняю не саму команду, а состояние графического редактора, а точнее его элементов.
Но в то же время и проще. Причем намного. По поводу патерна Команда, я полностью согласен, что это наиболее рациональный вариант, но в моем случае реализация затруднена, потому что многие действия в редакторе не являются коммандами (то же перемещение, вращение элементов, изменения размеров), кроме того сами элементы достаточно сложные, откат команды может забрать не меньше ресурсов, чем восстановление состояния (к примеру, после перемещения или удаления большого ко-ва элементов). Потому попытаюсь заменить XML-сериализацию на бинарную (буду сохранять такую же структуру, что и в XML, не целый объект), и если производительность будет удовлитворительной (в чем я сомневаюсь), так и оставлю. Если нет, буду думать по поводу патерна Команда. tol05, По поводу остальных паттернов - спасибо, ознакомлюсь для общего развития, но в рамках текущего проекта это избыточно. Спасибо всем за идеи. |
|||
|
||||
tol05 |
|
||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 63 Всего: 170 |
все таки я думаю что сохранение состояния - это крайне неправильная идея.... Особенно при испольовании WPF ! С его-то возможностями... что я имею в виду:
Т.к. команды Undo\Redo могут вызываться пользователем каким угодно образом. Например Shape89-Shape90-Undo-Undo-Redo-Redo-Undo-Undo-Redo-Shape50_1-Undo-Undo... и так - до бесконечности то, как я понимаю, Вы, Anyone, собираетесь каждый раз обнулять графический контейнер, поднимать файл, считывать его в память и перерисовывать все объекты?! (после чего все объекты заново сохранять в файл, конечно же) А не проще ли просто в случае Undo при помощи команды обратиться к контейнеру (Canvas-у например) с просьбой удалить из своих Children объект Shape89 (к примеру) и не трогать остальные 999 тысяч других Shapes??? А в случае Redo добавить в тот же контейнер только один Shape, а не стирать все 999 тысяч Shapes чтобы сразу же их нарисовать обратно + тот несчастный Shape89... P.S. пара комментариев еще
а что, опросить сложный объект, узнать его сложное внутреннее состояние (которое как-бы уже и не очень внутренним становится), подготовить эти данные к сохранению, сохранить, считать, подготовить рисование по этим данным - это все не сложно? Ну а про удаление большого кол-ва объектов... Это будет самой популярной операцией в Вашем редакторе. Это сообщение отредактировал(а) tol05 - 7.11.2009, 23:12 -------------------- На хорошей работе и сны хорошие снятся. |
||||||
|
|||||||
Anyone |
|
||||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Я бы давно это сделал, если бы за прорисовку отвечал я. Но WPF сам за меня это делает - я лишь определяю внешний вид. На самом деле вся сложность паттерна Комманда заключается в том, что я изначально не подготовил для него фундамент, придется много чего переделывать\доделывать. Но если производительность паттерна Хранитель меня не устроит (пользователь будет оценивать не способ реализации, а производительность, так зачем тратить кучу времени, если будет работать не плохо?), придется все таки это сделать.
Почему я должен обижаться, наоборот, спасибо за идеи. |
||||
|
|||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: нет Всего: 72 |
Можно добавить в окно скрытый (Rich)TextBox - пусть он занимается сохранением состояний для Undo/Redo, нужно только научиться синхронизировать состояение твоей канвы с текстом в TextBox
|
|||
|
||||
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Не совсем понятно зачем текст бокс, ведь можно использовать, для этого свой класс-одиночку? Что в нем хранить, ведь редактор то графический? Список комманд чтоле? |
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: нет Всего: 72 |
Наверно, у тебя есть команда Save где ты сохраняешь графику в виде xml? Вот этот xml и можно хранить в TextBox, а Undo/Redo для него уже реализованы. Но нужно уметь быстро синхронизировть этот xml с графикой, что может оказаться непростой задачей.
|
|||
|
||||
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Так именно в этом вся проблема, процесс десериализации XML-документа достаточно медленный, если много элементов. Еще хочу попробывать реализовать интерфейс ISerializable и использовать бинарную сериализацию, а потом, если не устроит, буду думать по поводу паттерна Команда. |
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: нет Всего: 72 |
Бинарная сериализация ускорит дело, но для большого документа всё равно будет медленно. Нужно сериализовать только те части, которые изменились. Возможно, RichTextBox будет удобнее - каждому графическому объекту задать в соответстие параграф с помощью присоединённого свойства или Map, хранящейся где-то отдельно. Сам объект может сохраняться не в xml.
Создание нового объекта - в RichTextBox появляется новый параграф, который сопоствавляется с этим объектом. Изменение объекта - вносятся изменения в параграф Удаление - параграф удаляется. Undo/Redo - вносятся изменения в объекты, чьи параграфы изменились, удаляются объекты, чьи параграфы удалились, создаются объекты для новых параграфов. Добавлено через 8 минут и 24 секунды Ещё можно сохранять редактируемые объекты в базу данных - так придётся делать для ОЧЕНЬ больщого документа, RichTextBox будет требовать слишком много памяти. |
|||
|
||||
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
math64,
Интересная идея, нужно попробывать. По поводу базы данных. А что если ее хранить в датасете, один объект - одна запись, скажем айдишка и свойства, сохранение программы - это сериализация датасета. А синхронизировать БД с редактором в отдельном потоке. Я правильно мыслю? |
|||
|
||||
Anyone |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 218 Регистрация: 1.6.2008 Репутация: нет Всего: нет |
Есть стандартные механизмы для реализации такой возможности, или нужно все самому продумать? Может есть какой-нить пример? |
|||
|
||||
![]() ![]() ![]() |
Прежде чем создать тему, посмотрите сюда: | |
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |