C#中通過(guò)Command模式實(shí)現(xiàn)Redo/Undo方案
一個(gè)比較常見(jiàn)的改進(jìn)用戶(hù)體驗(yàn)的方案是用Redo/Undo來(lái)取代確認(rèn)對(duì)話(huà)框,由于這個(gè)功能比較常用,本文簡(jiǎn)單的給了一個(gè)在C#中通過(guò)Command模式實(shí)現(xiàn)Redo/Undo方案的例子,以供后續(xù)查詢(xún)。
class Program
{
static void Main(string[] args)
{
var cmds = new CommandManager();
while (true)
{
var key = Console.ReadKey(true);
if (key.KeyChar >= '0' && key.KeyChar <= '9')
{
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 != 0; } }
public bool CanReDo { get { return ReDoActionStack.Count != 0; } }
//public IEnumerable<Command> Actions { get { return ReDoActionStack.Reverse().Concat(UnDoActionStack); } }
}原理很簡(jiǎn)單,通過(guò)Command模式把每一步操作封裝成一個(gè)可undo的命令(包含do和redo兩個(gè)操作)。并將每一步操作執(zhí)行后用棧保存起來(lái),undo的時(shí)候就以此將Command依次出棧,并執(zhí)行undo操作。(從某種意義上來(lái)說(shuō),redo就是undo操作的undo)
上面的代碼已經(jīng)實(shí)現(xiàn)了基本的Undo/Redo功能,但實(shí)際使用的時(shí)候還是有一些細(xì)節(jié)需要考慮的:如undo或redo時(shí)失?。⊕伄惓#┑奶幚淼?。由于這些細(xì)節(jié)方面的處理方式不盡相同,本文只是實(shí)現(xiàn)一個(gè)基本框架,以備后續(xù)使用時(shí)參考,并不想把它弄的過(guò)于復(fù)雜。
這種方式比較簡(jiǎn)單,幾乎每種語(yǔ)言都可以輕易的寫(xiě)出這種方式下的實(shí)現(xiàn)。但通過(guò)這種Command封裝的方式實(shí)現(xiàn)的也有一些限制,使用的時(shí)候需要注意:
- 每一步操作都需要封裝成command命令
- 每一步操作都是可逆的
- 當(dāng)命令過(guò)多的時(shí)候需要考慮commandlist的內(nèi)存占用和命令查詢(xún)時(shí)的性能問(wèn)題
到此這篇關(guān)于C#中通過(guò)Command模式實(shí)現(xiàn)Redo/Undo方案的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
c# Form中的鍵盤(pán)響應(yīng)具體實(shí)現(xiàn)思路
在全屏Form中加上鍵盤(pán)ESC的響應(yīng),實(shí)現(xiàn)的效果就是:全屏中press鍵盤(pán)上的Escape鍵,程序結(jié)束,具體實(shí)現(xiàn)步驟如下,感興趣的朋友可以參考下哈2013-06-06
C#設(shè)計(jì)模式編程中運(yùn)用適配器模式結(jié)構(gòu)實(shí)戰(zhàn)演練
這篇文章主要介紹了C#設(shè)計(jì)模式編程中運(yùn)用適配器模式結(jié)構(gòu)實(shí)戰(zhàn)演練,并總結(jié)了適配器模式的優(yōu)缺點(diǎn)和適用場(chǎng)景以及.NET框架中的應(yīng)用,需要的朋友可以參考下2016-02-02
C#難點(diǎn)逐個(gè)擊破(6):C#數(shù)據(jù)類(lèi)型與.net framework數(shù)據(jù)類(lèi)型
最近開(kāi)始看Illustrator C#2008,這真是一本好書(shū),我讀計(jì)算機(jī)書(shū)籍這么多了,能讓我稱(chēng)為好書(shū)的沒(méi)有多少。2010-02-02
C#使用Task實(shí)現(xiàn)執(zhí)行并行任務(wù)的原理的示例詳解
Task是一個(gè)表示異步操作的類(lèi),它提供了一種簡(jiǎn)單、輕量級(jí)的方式來(lái)創(chuàng)建多線(xiàn)程應(yīng)用程序。本文就來(lái)和大家聊聊在C#中如何使用Task執(zhí)行并行任務(wù)吧2023-04-04
C# SynchronizationContext以及Send和Post使用解讀
這篇文章主要介紹了C# SynchronizationContext以及Send和Post使用解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢(xún)算法
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)Nginx平滑加權(quán)輪詢(xún)算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07

