撤销与反撤销 功能实现

你一定经常看见类似下面的图标:

它们就表示“撤销”与“反撤销”。在程序中,这种功能通常是使用Command模式实现的,本文也不例外。首先抽象定义Command,使用ICommand接口:
public interface ICommand
{
void Excute();
}
Excute表示执行该 ICommand引用的目标的所包含的动作(或动作序列)。

可撤销的命令也是一种命令,所以从ICommand继承:

public interface IBackableCommand:ICommand
{
void Undo();
}
一个可撤销的命令表明调用其Excute方法后,再调用其Undo方法可以使被操作的对象回复到之前的状态。

为了实现撤销功能,我们需要一个堆栈来记录所有已执行的可撤销命令,为了实现反撤销的功能,同样,我们也需要一个堆栈来记录所有已撤销的命令。这个职责是由ICommandManager接口提供:

public interface ICommandManager
{
void ExcuteCommand(ICommandcommand);
void Undo();
void ReverseUndo(); // 反撤销

// 以下事件可用于控制撤销与反撤销图标的启用
event CbSimpleBoolUndoStateChanged; // bool参数表明当前是否有可撤销的操作
event CbSimpleBoolReverseUndoStateChanged; // bool参数表明当前是否有可反撤销的操作
}

现在,我们来详细分析一下,撤销命令堆栈和反撤销命令堆栈在何时Push命令对象、又在何时Pop命令对象:
(1)当执行完任何一个command后,reverseUndo堆栈清空
(2)当执行完一个不可撤销的command后,undo堆栈清空
(3)当执行完一个可撤销的command后,将其压入undo堆栈
(4)当撤销一个command后,将其转移到reverseUndo堆栈

基于此,我们就可以实现ICommandManager:
public class CommandManager:ICommandManager
{
private StackundoStack = new Stack();
private StackreverseStack = new Stack();

public event CbSimpleBoolUndoStateChanged;
public event CbSimpleBoolReverseUndoStateChanged;

public CommandManager()
{
this .UndoStateChanged += new CbSimpleBool(CommandManager_UndoStateChanged);
this .ReverseUndoStateChanged += new CbSimpleBool(CommandManager_UndoStateChanged);
}

private void CommandManager_UndoStateChanged( bool val)
{

}

#region ICommandManager成员

public void ExcuteCommand(ICommandcommand)
{
command.Excute();
this .reverseStack.Clear();

if (command is IBackableCommand)
{
this .undoStack.Push(command);
}
else
{
this .undoStack.Clear();
}

this .UndoStateChanged( this .undoStack.Count > 0 );
}

public void Undo()
{
IBackableCommandcommand
= (IBackableCommand) this .undoStack.Pop();
if (command == null )
{
return ;
}

command.Undo();
this .reverseStack.Push(command);

this .ReverseUndoStateChanged( this .reverseStack.Count > 0 );
}

public void ReverseUndo()
{
IBackableCommandcommand
= (IBackableCommand) this .reverseStack.Pop();
if (command == null )
{
return ;
}

command.Excute();
this .undoStack.Push(command);

this .UndoStateChanged( this .undoStack.Count > 0 );
this .ReverseUndoStateChanged( this .reverseStack.Count > 0 );
}
#endregion
}

本文介绍的撤销与反撤销功能是与应用无关的,所以可以在不同的应用中复用,你只需要根据你自己的应用需求来实现对应的ICommand接口和IBackableCommand接口就可以立即使用撤销与反撤销功能了。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值