上下文:
我正在尝试使用Command模式和WPF来实现undo/redo。
我将命令作为ViewModel的属性来操作数据。我在视图中绑定到这些命令。(对于上下文,我主要使用这些命令操作对象的集合。该集合用作DataGrid的ItemsSource)
可以撤消的命令实现此接口:
public interface IUndoableCommand : ICommand
{
public void Undo();
}
我维护了这些UndoableCommands
的堆栈。当UndoableCommand
被执行时,它被压入堆栈。当我想撤销时,我从堆栈中弹出这些命令中的一个,并执行它的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上下文之外用Command模式实现撤销的例子,或者用不需要状态的Undo()
方法实现撤销的例子。我想这是一个常见的场景。我的想法是不是都错了?这个问题有没有一致同意的解决方案?
我想做的事情是:
1.创建命令的深层副本并将其压入撤消堆栈。
1.让View绑定的命令创建我实际要执行的命令的示例。
1条答案
按热度按时间llycmphe1#
我处理Undo的方法是将UI层与底层的Undo机制分离。仅仅因为“command pattern”和“ICommand”都有工作“command”并不意味着它们需要或应该是同一个对象层次结构的一部分。
因此,您的
DeleteFromList
-命令可能如下所示:和wpf命令(如
要真正撤消一个操作,您需要一个单独的wpf命令,它会请求撤消堆栈弹出最后一个撤消对象,并运行它的撤消方法(如果这样的对象可用)。
这将把状态从wpf命令中移到一个单独的对象中,从而巧妙地避免了这个问题。
然而,我也会考虑只保存应用程序的完整状态。每种方法都有其优点,但您可能希望能够保存状态。通常,此状态只有几千字节,因此您可能可以维护数百个撤消状态,而无需担心内存问题。