转:C#中Undo/Redo的一个简易实现
一个比较常见的改进用户体验的方案是用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封装的方式实现的也有一些限制,使用的时候需要注意:
- 每一步操作都需要封装成command命令
- 每一步操作都是可逆的
- 当命令过多的时候需要考虑commandlist的内存占用和命令查询时的性能问题
转:C#中Undo/Redo的一个简易实现的更多相关文章
- 说说MySQL中的Redo log Undo log都在干啥
在数据库系统中,既有存放数据的文件,也有存放日志的文件.日志在内存中也是有缓存Log buffer,也有磁盘文件log file,本文主要描述存放日志的文件. MySQL中的日志文件, ...
- 【转】说说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 空间管理 ...
- Oracle 中UNDO与REDO的差别具体解释
一 为了更清楚的看出2者差别,请看下表: UNDO ...
- MySQL中的redo log和undo log
MySQL中的redo log和undo log MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎 ...
- 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具
查看本章节 查看作业目录 需求说明: 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具 实现思路: 使用history对象中的 forward() 方法和 ...
- MySQL,MariaDB:Undo | Redo [转]
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...
- iOS: 为画板App增加 Undo/Redo(撤销/重做)操作
这个随笔的内容以上一个随笔为基础,(在iOS中实现一个简单的画板),上一个随笔实现了一个简单的画板: 今天我们要为这个画板增加Undo/Redo操作,当画错了一笔,可以撤销它,或者撤销之后后悔了, ...
- [转]MySQL日志——Undo | Redo
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...
- 从Undo,Redo谈命令模式
一般的应用软件中,通常会提供Redo和Undo的操作,比如Paint.NET中的动作面板,Word中的撤销重做,一般我们按Ctrl-Z即可回退到上次操作. 要实现上面的这一功能,最直观的想法就是,我们 ...
随机推荐
- Android手机用wifi连接adb调试的方法
https://www.jianshu.com/p/dc6898380e38 0x0 前言 Android开发肯定要连接pc的adb进行调试,传统的方法是用usb与pc进行连接,操作简单即插即用,缺点 ...
- 4 playlook-Jinja2 filter
jinja2模板,不多解释,请看例子 [root@LeoDevops jinjatwo]# cat j1.yaml - hosts: u12 gather_facts: False vars: lis ...
- python从FTP下载文件
#!/usr/bin/python # -*- coding: utf-8 -*- """ FTP常用操作 """ from ftplib ...
- python使用微信推送消息
from wxpy import * #该库主要是用来模拟与对接微信操作的 import requests from datetime import datetime import time impo ...
- 腾讯云云机安装dockers
云机的配置 首先更新一下源(更新前一直装不了) 下载dockers-ce(社区版) 启动dockers服务 使用hello-world进行测试(由于本地没有hello-world这个镜像,所以dock ...
- react 路由导航栏 withRouter
codesandbox https://codesandbox.io/s/9l6prnyxjy app.js import React, { Component, Fragment } from &q ...
- 小tip: transition与visibility
一.transition与visibility 这里的transition指的就是CSS3中的那个过渡动画属性transition. 如果我们仔细查看其支持的CSS属性值,会发现竟然有一个visibi ...
- WebH
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...
- Luogu 1031 - 均分纸牌 - [有意思的思维题]
题目链接:https://www.luogu.org/problemnew/show/P1031 题目描述有 $N$ 堆纸牌,编号分别为 $1,2,…,N$.每堆上有若干张,但纸牌总数必为 $N$ 的 ...
- JVM—内存溢出、OutOfMemoryError、StackOverflowError
学习jvm时看到几篇非常好的系列文章,转载了: <深入理解Java虚拟机>学习小记一之自动内存管理机制(一) http://my.oschina.net/linuxfelix/blog/1 ...