2010-12-02 34 views
3

我已經做了一些研究,以瞭解如何實現這個問題的標題。我正在開發的應用程序已經開發了幾年左右(儘管進展緩慢,你們都知道它是如何在真實世界中)。現在我需要放入撤銷/重做多級功能。現在說「在開始之前你應該考慮過這個問題」有點晚了......呃,我們確實考慮過這個問題 - 而且我們對此沒有采取任何措施,現在就是這樣。從摸索SO(和外部鏈接),我可以看到,這兩個最常見的方法似乎是...在已經功能的應用程序中撤消WPF/C#中的重做

Command Pattern

Memento Pattern

Command模式看起來這將是一個地獄很多工作,我只能想象它會在這個過程中拋出成千上萬的錯誤,所以我並不喜歡那個。

Memento模式實際上很像我在我腦中爲此所做的。我正在考慮是否有辦法快速獲取當前內存中的對象模型的快照,然後我可以將它存儲在某處(也可能存儲在內存中,也可能存儲在文件中)。這似乎是一個好主意,我能看到的唯一問題就是它如何與我們已經寫過的內容整合。您可以看到應用程序,因爲它可以在大面板中繪製圖像(可能有數百個),然後允許用戶通過UI或通過自定義構建的屬性網格來操作它們。整個應用程序與大觀察員模式相關聯。第二件事情發生了變化,事件被解僱了,所有需要更新的事情都發生了。這很好,但我不能幫助你想,如果用戶在屬性網格中輸入文本到texfield,那麼在用戶界面趕上之前會有一點延遲(看起來每次用戶按下一個鍵時都會添加一個新的快照到撤消列表)。所以我對你的問題是......

  • 你知道任何可以替代Memento模式,可能工作。
  • 您是否認爲Memento模式適合這裏,或者它會讓應用程序的速度變慢。
  • 如果Memento模式是要走的路,那麼創建對象模型快照的最有效方法是什麼(我在想連載它或什麼)
  • 如果快照存儲在內存中或者是否可能把它們放到文件中?

如果你有這麼多,謝謝你的閱讀。你有任何輸入將是有價值的,非常感謝。

回答

1

爲撤銷/重做關鍵的事情是

  • 知道你需要什麼樣的狀態保存和恢復
  • 知道什麼時候你需要保存狀態

添加撤消/後重做事實上總是一件痛苦的事情 - (我知道這個評論現在對你來說毫無用處,但最好在開始之前爲應用程序框架設計支持,因爲它有助於人們在整個開發過程中使用對友好的模式)。

也許最簡單的方法將是一個紀念基於一個:

  • 找到所有這些都是你的「文件」中的數據。你能否以某種方式統一這些數據,從而形成一個連貫的整體?通常,如果你可以將你的文檔結構串行化爲一個文件,你需要的邏輯就是在序列化系統中,這樣可以給你一個方法。直接使用它的缺點通常是你通常必須序列化所有的東西,將是巨大而緩慢的。如果可能的話,重構代碼以便(a)在整個應用程序中使用通用的序列化接口(因此可以使用通用調用來保存/恢復數據的任何部分),以及(b)每個子系統都被封裝所以對數據的修改必須經過一個通用的接口(而不是許多人直接修改成員變量,他們都應該調用由對象提供的API來請求對其自身進行修改),以及(c)部分數據保留「版本號」。每次進行更改(通過(b)中的界面),都應該增加該版本號。這種方法意味着您現在可以掃描整個文檔並使用版本號查找自上次查看以來發生更改的部分,然後將最小數量序列化以保存並恢復更改後的狀態。

    • 提供一種可以記錄單個撤銷步驟的機制。這意味着允許多重系統對數據結構進行更改,然後在更新所有內容時觸發撤消記錄。確定何時執行此操作可能會非常棘手,但通常可以通過在您的UI完成處理每個輸入事件後,掃描文檔以查看消息循環中的更改(請參閱上文)來完成。

除此之外,我建議去一個命令爲基礎的方法,因爲有很多好處,它除了撤銷/重做。

5

嗯,這是我對這個問題的想法。

1-您需要多級撤銷/重做功能。因此您需要存儲可以存儲在堆棧中的用戶操作。

2-你的第二個問題如何確定什麼被我認爲通過Memento模式的操作所改變,這是一個相當大的挑戰。紀念是關於在你的記憶中摧毀最初的對象狀態。

要麼你需要存儲操作所改變的內容,以便你可以使用這些信息來撤銷操作。

命令模式是爲撤銷/重做功能而設計的,我會說它的後期但它的價值,同時實現了多年來使用的設計,並且適用於大多數應用程序。

+1

+1當你說撤銷/重做你自動說命令模式。無論簡單還是難以實施。 – 2010-12-02 18:16:03

+0

目前的應用程序完全與觀察員聯繫。讓應用程序創建一個「紀念品」就像編寫函數來創建它,然後訂閱看守人到所需的觀察者一樣簡單。我沒有把心放在紀念品上,但我傾向於它。否則我會很高興地相信。 – DrLazer 2010-12-02 18:28:20

3

如果性能允許,您可以在每次操作之前序列化您的域。如果對象本身不大,幾百個對象就不多了。

由於您的對象圖可能不是微不足道的(即使用繼承,循環,...)集成的XmlSerializer和JsonSerializers是沒有問題的。 Json.net支持這些,但是對某些類型(本地日期時間,數字...)進行一些有損轉換,所以它也不好。

我認爲protobuf序列化器需要某種形式的DTD(.proto文件)或裝飾所有屬性的屬性將它們的名稱映射到一個數字,因此它可能不是最優的。

BinaryFormatter可以序列化大多數東西,你只需要用[Serializable]屬性來修飾所有的類。但我自己並沒有使用它,所以可能會有我不知道的陷阱。也許與單身人士或事件有關。

+0

我當時希望情況會如此。使用Memento模式並以某種序列化狀態保存對象模型。你知道一個快速的方法來做這樣的事情嗎? – DrLazer 2010-12-02 19:04:09

1

您可能會發現「受監視的撤消框架」非常有用。 http://muf.codeplex.com/

它使用類似於備忘錄模式的方式,通過在發生變化時監視更改並允許您將委託放置在將撤消/重做更改的撤消堆棧上。

我考慮過一種可以序列化/反序列化文檔但是擔心開銷的方法。相反,我通過物業基地來監控房產模型(或視圖模型)的變化。然後,根據需要,我使用MUF庫對相關更改進行「批處理」,以便它們以撤銷/重做爲單位進行更改。

事實上,你有你的UI設置來對底層模型的變化作出反應是很好的。這聽起來像是你可以在那裏注入撤銷/重做邏輯,並且這些改變會向用戶界面發起泡沫。

我不認爲你會看到很多滯後或性能下降。我有一個類似的應用程序,我們根據模型中的數據繪製了一個圖表。迄今爲止,我們已經取得了不錯的成績。

你可以在codeplex網站上找到更多的信息和文檔在http://muf.codeplex.com/。該庫也可以通過NuGet獲得,支持.NET 3.5,4.0,SL4和WP7。

相關問題