windows phone 7--8 Belling课堂(十六) 文本编辑器中, 如何设计 撤销/重复栈

        在文本编辑中经常使用到“撤销”操作(Ctrl-Z),以及一个与之相应的“重复”操作(Ctrl-Y),各种不同的编辑操作都可以使用这两个操作来撤销或重复,那么如此多的编辑操作是如何被设计到一起而使得一个“撤销”按钮可以撤销各种不同的操作呢?

关键在于两点:栈 和 多态。

如何设计:
       很容易想到使用栈来保持那些已经被执行的操作,当要撤销上一步操作时,只需要取出栈顶元素并执行该元素所对应的操作便可。
     接踵而至的一个问题是: 栈中元素类型是什么? 由于我们需要保存各种不同的文本编辑操作,要将它们统一地保存在一起,很自然地,我们应该让这些操作有着统一的父类, 我们栈中元素的类型是该父类类型就可以了.
     我们这里设计了一个接口,所有的可撤销/重复的操作都应该继承该接口:


     ///   <summary>
     ///  可撤销重复操作接口。
     ///  所有的可重复可撤销的操作都应该继承这个接口。
     ///   </summary>
     interface  IUndoableOperate
    {
         void  Undo();
         void  Redo();
         void  Execute();
    }


       比如我们有一个操作Operate1,它继承了IUndoableOperate接口


     ///   <summary>
     ///  操作1
     ///   </summary>
     class  Operate1 : IUndoableOperate
    {
         #region  IUndoableOperate 成员

         ///   <summary>
         ///  撤销该操作时执行
         ///   </summary>
         public   void  Undo()
        {
            Console.WriteLine( " undo operate1 " );
        }

         ///   <summary>
         ///  重复该操作时执行
         ///   </summary>
         public   void  Redo()
        {
            Console.WriteLine( " do operate1 " );
        }

         ///   <summary>
         ///  执行操作1
         ///   </summary>
         public   void  Execute()
        {
             this .Redo();
        }

         #endregion

    }


       其它任何与Operate1类似的操作都可以放到撤销栈中,以便以后撤销。

       栈中元素都是IUndoableOperate类型,那么当我们取出栈顶元素并调用其Execute()函数时,其能被正确的执行吗?答案是肯定的,这利用了多态。

       现在我们可以设计一个管理器来对栈进行管理,它将记录那些被执行或被撤销的操作,并提供方法允许你对已经执行过的操作进行撤销、已经撤销的操作进行重复。


     /// <summary>
    /// 撤销重复操作管理器
    /// </summary>

     class  UndoStackManager
     {
        /// <summary>
        /// 撤销栈
        /// </summary>

        Stack<IUndoableOperate> un_stack = new Stack<IUndoableOperate>();
        /// <summary>
        /// 重复栈
        /// </summary>

        Stack<IUndoableOperate> re_stack = new Stack<IUndoableOperate>();


        public void ClearStack()
        {
            this.un_stack.Clear();
            this.re_stack.Clear();
        }


        /// <summary>
        /// 获取一个值,指示是否有可撤销的操作
        /// </summary>

        public bool CanUndo
        {
            get
            {
                return un_stack.Count != 0;
            }

        }


        /// <summary>
        /// 获取一个值,指示是否有可重复的操作
        /// </summary>

        public bool CanRedo
        {
            get
            {
                return re_stack.Count != 0;
            }

        }


        /// <summary>
        /// 撤销上一操作
        /// </summary>

        public void Undo()
        {
            if (this.CanUndo)
            {
                IUndoableOperate op = un_stack.Pop();
                op.Undo();
                re_stack.Push(op);
            }

        }


        /// <summary>
        /// 重复被撤销的操作
        /// </summary>

        public void Redo()
        {
            if (this.CanRedo)
            {
                IUndoableOperate op = re_stack.Pop();
                op.Redo();
                un_stack.Push(op);
            }

        }



        /// <summary>
        /// 将某一操作存放到撤销栈中
        /// </summary>
        /// <param name="op"></param>

        public void PushToUndoStack(IUndoableOperate op)
        {
            this.un_stack.Push(op);
            this.re_stack.Clear();
        }

    }


     以下是完整的示例代码:


  1using System;
  2using System.Collections.Generic;
  3using System.Text;
  4
  5namespace UndoRedo
  6{
  7    class Program
  8    {
  9        static void Main(string[] args)
 10        {
 11            //声明一个管理器
 12            UndoStackManager manager = new UndoStackManager();
 13
 14            //执行一些操作
 15            Operate1 op1 = new Operate1();
 16            op1.Execute();
 17            manager.PushToUndoStack(op1);
 18
 19            Operate2 op2 = new Operate2();
 20            op2.Execute();
 21            manager.PushToUndoStack(op2);
 22
 23            //撤销执行的操作
 24            manager.Undo();
 25            manager.Undo();
 26
 27            //重复被撤销的操作
 28            manager.Redo();
 29            manager.Redo();
 30        }

 31    }

 32
 33
 34    /// <summary>
 35    /// 可撤销重复操作接口。
 36    /// 所有的可重复可撤销的操作都应该继承这个接口。
 37    /// </summary>

 38    interface IUndoableOperate
 39    {
 40        void Undo();
 41        void Redo();
 42        void Execute();
 43    }

 44
 45    /// <summary>
 46    /// 操作1
 47    /// </summary>

 48    class Operate1 : IUndoableOperate
 49    {
 50        IUndoableOperate 成员
 77
 78    }

 79
 80
 81    /// <summary>
 82    /// 操作1
 83    /// </summary>

 84    class Operate2 : IUndoableOperate
 85    {
 86        IUndoableOperate 成员
113    }

114
115    /// <summary>
116    /// 撤销重复操作管理器
117    /// </summary>

118    class UndoStackManager
119    {
120        /// <summary>
121        /// 撤销栈
122        /// </summary>

123        Stack<IUndoableOperate> un_stack = new Stack<IUndoableOperate>();
124        /// <summary>
125        /// 重复栈
126        /// </summary>

127        Stack<IUndoableOperate> re_stack = new Stack<IUndoableOperate>();
128
129
130        public void ClearStack()
131        {
132            this.un_stack.Clear();
133            this.re_stack.Clear();
134        }

135
136        /// <summary>
137        /// 获取一个值,指示是否有可撤销的操作
138        /// </summary>

139        public bool CanUndo
140        {
141            get
142            {
143                return un_stack.Count != 0;
144            }

145        }

146
147        /// <summary>
148        /// 获取一个值,指示是否有可重复的操作
149        /// </summary>

150        public bool CanRedo
151        {
152            get
153            {
154                return re_stack.Count != 0;
155            }

156        }

157
158        /// <summary>
159        /// 撤销上一操作
160        /// </summary>

161        public void Undo()
162        {
163            if (this.CanUndo)
164            {
165                IUndoableOperate op = un_stack.Pop();
166                op.Undo();
167                re_stack.Push(op);
168            }

169        }

170
171        /// <summary>
172        /// 重复被撤销的操作
173        /// </summary>

174        public void Redo()
175        {
176            if (this.CanRedo)
177            {
178                IUndoableOperate op = re_stack.Pop();
179                op.Redo();
180                un_stack.Push(op);
181            }

182        }

183
184
185        /// <summary>
186        /// 将某一操作存放到撤销栈中
187        /// </summary>
188        /// <param name="op"></param>

189        public void PushToUndoStack(IUndoableOperate op)
190        {
191            this.un_stack.Push(op);
192            this.re_stack.Clear();
193        }

194    }

195}

196


示例代码的执行结果是:
do operate1
do operate2
undo operate2
undo operate1
do operate1
do operate2

转载于:https://www.cnblogs.com/Belling/archive/2012/12/20/2827130.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值