一个比较常见的改进用户体验的方案是用Redo/Undo来取代确认对话框,由于这个功能比较常用,本文简单的给了一个在C#中通过Command模式实现Redo/Undo方案的例子,以供后续查询。

class Program
{
static void Main(string[] args)
{
var cmds = new CommandManager();
while (true)
{
var key = Console.ReadKey(true);
if (key.KeyChar >= '' && key.KeyChar <= '')
{
cmds.DoNewCommand(key.KeyChar.ToString(), () => Console.WriteLine("process " + key.KeyChar), () => Console.WriteLine("redo " + key.KeyChar));
}
else
{
if (key.Modifiers.HasFlag(ConsoleModifiers.Control) && (key.Key == ConsoleKey.Z))
cmds.UnDo();
else if (key.Modifiers.HasFlag(ConsoleModifiers.Control) && (key.Key == ConsoleKey.Y))
cmds.ReDo();
}
}
}
} class CommandManager
{
#region Command定义
public class Command
{
string name;
Action action;
Action unDoAction; internal Command(string name, Action action, Action unDoAction)
{
this.name = name;
this.action = action;
this.unDoAction = unDoAction;
} internal void Do() { action(); }
internal void UnDo() { unDoAction(); } public override string ToString()
{
return name.ToString();
}
}
#endregion public Stack<Command> ReDoActionStack { get; private set; }
public Stack<Command> UnDoActionStack { get; private set; } public CommandManager()
{
ReDoActionStack = new Stack<Command>();
UnDoActionStack = new Stack<Command>();
} public void DoNewCommand(string name, Action action, Action unDoAction)
{
var cmd = new Command(name, action, unDoAction);
UnDoActionStack.Push(cmd);
ReDoActionStack.Clear();
cmd.Do();
} public void UnDo()
{
if (!CanUnDo)
return; var cmd = UnDoActionStack.Pop();
ReDoActionStack.Push(cmd);
cmd.UnDo();
} public void ReDo()
{
if (!CanReDo)
return; var cmd = ReDoActionStack.Pop();
UnDoActionStack.Push(cmd);
cmd.Do();
} public bool CanUnDo { get { return UnDoActionStack.Count != ; } }
public bool CanReDo { get { return ReDoActionStack.Count != ; } }
//public IEnumerable<Command> Actions { get { return ReDoActionStack.Reverse().Concat(UnDoActionStack); } }
}

代码

原理很简单,通过Command模式把每一步操作封装成一个可undo的命令(包含do和redo两个操作)。并将每一步操作执行后用栈保存起来,undo的时候就以此将Command依次出栈,并执行undo操作。(从某种意义上来说,redo就是undo操作的undo)

上面的代码已经实现了基本的Undo/Redo功能,但实际使用的时候还是有一些细节需要考虑的:如undo或redo时失败(抛异常)的处理等。由于这些细节方面的处理方式不尽相同,本文只是实现一个基本框架,以备后续使用时参考,并不想把它弄的过于复杂。

这种方式比较简单,几乎每种语言都可以轻易的写出这种方式下的实现。但通过这种Command封装的方式实现的也有一些限制,使用的时候需要注意:

  1. 每一步操作都需要封装成command命令
  2. 每一步操作都是可逆的
  3. 当命令过多的时候需要考虑commandlist的内存占用和命令查询时的性能问题

转:C#中Undo/Redo的一个简易实现的更多相关文章

  1. 说说MySQL中的Redo log Undo log都在干啥

        在数据库系统中,既有存放数据的文件,也有存放日志的文件.日志在内存中也是有缓存Log buffer,也有磁盘文件log file,本文主要描述存放日志的文件.     MySQL中的日志文件, ...

  2. 【转】说说MySQL中的Redo log Undo log都在干啥

    阅读目录(Content) 1 undo 1.1 undo是啥 1.2 undo参数 1.3 undo空间管理 2 redo 2.1 redo是啥 2.2 redo 参数 2.3 redo 空间管理 ...

  3. Oracle 中UNDO与REDO的差别具体解释

    一 为了更清楚的看出2者差别,请看下表:                                               UNDO                             ...

  4. MySQL中的redo log和undo log

    MySQL中的redo log和undo log MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎 ...

  5. 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具

    查看本章节 查看作业目录 需求说明: 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具 实现思路: 使用history对象中的 forward() 方法和 ...

  6. MySQL,MariaDB:Undo | Redo [转]

    本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...

  7. iOS: 为画板App增加 Undo/Redo(撤销/重做)操作

    这个随笔的内容以上一个随笔为基础,(在iOS中实现一个简单的画板),上一个随笔实现了一个简单的画板:   今天我们要为这个画板增加Undo/Redo操作,当画错了一笔,可以撤销它,或者撤销之后后悔了, ...

  8. [转]MySQL日志——Undo | Redo

    本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...

  9. 从Undo,Redo谈命令模式

    一般的应用软件中,通常会提供Redo和Undo的操作,比如Paint.NET中的动作面板,Word中的撤销重做,一般我们按Ctrl-Z即可回退到上次操作. 要实现上面的这一功能,最直观的想法就是,我们 ...

随机推荐

  1. 24小时学通Linux内核之构建Linux内核

    今天是腊八节,说好的女票要给我做的腊八粥就这样泡汤了,好伤心,好心酸呀,看来代码写久了真的是惹人烦滴,所以告诫各位技术男敲醒警钟,不要想我看齐,不然就只能和代码为伴了的~~话说没了腊八粥但还是有代码, ...

  2. ArcGIS删除数据异常崩溃

    环境 ArcGIS Desktop10.1,ArcSDE10.1,Oracle 11.2.0.4客户端和服务器端(服务器端搭建RAC集群) 问题描述 在使用ArcCatalog连接数据库进行数据删除时 ...

  3. Axure RP 9 Beta 开放下载(更新激活密钥和汉化包)

    2018年9月9号,7月9号来厦门入职,已经两个月了.这两个月的生活状态真心不好,一方面工作很忙(刚工作是这样?),虽然工资还可以,但总感觉性价比很低,自已对这份工作不够热爱也许.另一方面,来到新城市 ...

  4. word2vec:基本的安装及使用简介

    官方word2vec的github下载地址:https://github.com/svn2github/word2vec 环境,linux-ubuntu-14.04LST,安装好git, gcc版本4 ...

  5. Java中的 内部类(吐血总结)

    1. 内部类的作用 内部类是一个独立的实体,可以用来实现闭包:能与外部类通信:内部类与接口使得多继承更完整 2. 内部类的分类 1)普通内部类 类的实例相关,可以看成是一个实例变量.内部类的类名由 “ ...

  6. js获取当前日期方法(YYYY-MM-DD格式)

      var myDate = new Date(); var time = myDate.toLocaleDateString().split('/').join('-');将1970/08/08转化 ...

  7. java JVM虚拟机

    JVM垃圾处理方法(标记清除.复制.标记整理) 1.标记清除 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象. 清除阶段:清除所有未被标记的对象. 2.复制算法 将原有的空间 ...

  8. 1.7Oob对象的创建局部变量

    1:局部变量不会被系统自动初始化,所以局部变量必须进行初始化操作. 2:break是跳出当前循环体,return是跳出当前循环体和方法 并且结束外围循环体和方法,continue是跳过本次循环 3:创 ...

  9. Hadoop开发环境配置1-maven安装配置

    1.下载maven安装包:apache-maven-3.3.9-bin.zip 下载地址: http://archive.apache.org/dist/maven/maven-3/3.3.9/bin ...

  10. Fiddler (进阶)内置命令与断点

    Fiddler 内置命令与断点 命令 对应请求项 介绍 示例 ? All 问号后边跟一个字符串,可以匹配出包含这个字符串的请求 ?google > Body 大于号后面跟一个数字,可以匹配出请求 ...