語境:
我正在嘗試使用命令模式和 WPF 實作撤消/重做。
我有命令作為操作資料的 ViewModel 的屬性。我在視圖中系結到這些命令。(對于背景關系,我主要是使用這些命令操作物件集合。該集合用作 DataGrid 的 ItemsSource)
可以撤銷的命令實作了這個介面:
public interface IUndoableCommand : ICommand
{
public void Undo();
}
我維護了一堆這些UndoableCommands。當 anUndoableCommand被執行時,它被壓入堆疊。當我想撤消時,我從堆疊中彈出這些命令之一,然后執行它的Undo()方法。
問題:
為許多命令實作該Undo()方法不需要記住任何狀態。在他們這樣做的情況下,我遇到了麻煩。
例如,如果我想從帶有 的串列中洗掉一個專案UndoableCommand,我可以將洗掉的專案存盤在命令物件本身中。就像是:
public class DeleteItemCommand : IUndoableCommand
{
private object _deletedItem;
public void Execute()
{
// Remove the item from the collection and set to _deletedItem
}
public void Undo()
{
// Insert the deletedItem back
}
}
這個問題是我系結到這樣的命令:
private IUndoableCommand _DeleteCommand;
public IUndoableCommand DeleteCommand
{
get
{
if(_DeleteCommand == null)
{
_DeleteCommand = new DeleteItemCommand();
}
return _DeleteCommand;
}
}
DeleteItemCommand每次需要呼叫命令時都不會創建新實體。這是同一個物件。以這種方式存盤已洗掉的專案是行不通的。
我環顧四周,但只能找到在 WPF DataBinding 背景關系之外使用命令模式或使用Undo()不需要狀態的方法實作撤消的示例。我想這是一個常見的場景。我在想這一切都錯了嗎?是否有一些商定的解決方案來解決這個問題?
我想過要做的事情是:
- 創建命令的深層副本并將其推入撤消堆疊。
- 擁有視圖系結的命令以創建我實際想要執行的命令的實體。
uj5u.com熱心網友回復:
我處理撤消的方法是將 UI 層與底層撤消機制分開。僅僅因為“命令模式”和“ICommand”都有作業“命令”并不意味著它們需要或應該屬于同一物件層次結構。
所以你的DeleteFromList-command 可能看起來像:
public class DeleteFromList<T> : IMyUndoObject{
private T item;
private List<T> list;
public DeleteFromList<T>(T item, List<T> list) => (item, list) = (item, list);
public void Undo() => list.Add(item);
}
和你的 wpf 命令一樣
public class DeleteLastFooCommand : ICommand{
private List<Foo> foos;
private MyUndoStack undoStack;
public DeleteFooCommand(List<Foo> foos, MyUndoStack undoStack) => (foos, undoStack) = (foos, undoStack);
public void Execute(){
var removed = foos.Last();
foos.RemoveAt(foos.Count - 1);
undoStack.Push(new DeleteFromList<Foo>(removed, foos));
}
要實際撤消操作,您將有一個單獨的 wpf 命令,它會友好地要求撤消堆疊彈出最后一個撤消物件并運行它的撤消方法,如果這樣的物件可用的話。
這將狀態從您的 wpf 命令移動到一個單獨的物件,因此巧妙地避免了這個問題。
但是,我也會考慮只保存應用程式的完整狀態。每種方法都有其優點,但您可能希望無論如何都能夠保存狀態。通常,此狀態只有幾千位元組,因此您可以維護數百個撤消狀態而無需擔心記憶體。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/535025.html
下一篇:多處理:實體在迭代時不受影響
