项目中撤消与反撤消实现

  最近运维提出要实现撤销与反撤销的功能:

背景与图片示例。运行图如下:

 

针对上图,右键可以实现的如下功能

 

  针对右键的功能可以对dev中的GridControl插入、剪切、删除等操作。操作过程中可能出错,需要返回上一步。

实现思路。使用Stack(后进先出),使用图像表示。

BackDataTable记录每一步的操作。如下图所示

当按下返回按键时,BackDataTable中的数据pop出栈,push压入AfterDataTable栈中.如下图所示

当按下返回按键时,AfterDataTable中的数据pop出栈,push压入BackDataTable栈中.

  

实现代码:

代码段一:在程序加载时,即Load事件中初始化和注册事件。

            //撤销和反撤销有关信息
            BackDataTable.Clear();            //清空堆栈
            AfterDataTable.Clear();           //清空堆栈
            simBtnBack.Visible = false;       //回退按钮不可见
            simBtnAfter.Visible = false;      //前进按钮不可见
            simBtnBack.Enabled = false;       //回退按钮不可用
            simBtnAfter.Enabled = false;      //前进按钮不可用

            simBtnBack.Click += (obj, arg) => 
                  UnDoBeforeOrAfter(ref BackDataTable, ref AfterDataTable, true); //注册回退按纽事件 simBtnAfter.Click += (obj, arg) =>
                  UnDoBeforeOrAfter(ref BackDataTable, ref AfterDataTable, false); //注册前进按纽事件 loaded = true; this.KeyDown += (obj, key) => { if (key.Control && key.KeyCode == Keys.Z) // 撤销 UnDoBeforeOrAfter(ref BackDataTable, ref AfterDataTable, true); if (key.Control && key.KeyCode == Keys.Y) // 反撤销 UnDoBeforeOrAfter(ref BackDataTable, ref AfterDataTable, false); };


代码段二:获取数据保存每一步操作的数据

                var table = this.gridOperatorTask.DataSource as DataTable;    
                if (table != null)
                {
                    var copy = table.Copy();
                    if (!BackDataTable.Contains(copy))
                    {
                        BackDataTable.Push(copy);          //数据入栈
                    }
                    simBtnBack.Visible = BackDataTable.Count > 0;
                    simBtnBack.Enabled = BackDataTable.Count > 0;

                }

代码段三:UnDoBeforeOrAfter函数的实现

        private void UnDoBeforeOrAfter(ref Stack<DataTable> backDataTable, ref Stack<DataTable> afterDataTable, bool flag)
        {
            DataTable dt = null;
            FlagUndo = false;
            if (flag)   //撤销 
            {
                if (backDataTable.Count <= 0)
                    return;
                dt = backDataTable.Pop();   //出栈
                afterDataTable.Push(dt);    //入栈
                simBtnBack.Enabled = backDataTable.Count > 0;
                simBtnAfter.Visible = AfterDataTable.Count > 0;
                simBtnAfter.Enabled = afterDataTable.Count > 0;

            }
            if (!flag)  //反撤销 
            {
                if (afterDataTable.Count <= 0)
                    return;
                dt = afterDataTable.Pop();  //出栈
                backDataTable.Push(dt);     //入栈
                simBtnBack.Enabled = backDataTable.Count > 0;
                simBtnAfter.Enabled = afterDataTable.Count > 0;
            }
            var dtTemp = gridOperatorTask.DataSource as DataTable;
            if (dtTemp == null) return;
            var dtTempCopy = dtTemp.Copy();
            if (dtTempCopy.DataTableEquals(dt))  //DataTableEquals函数是扩展函数
            {
                gridOperatorTask.DataSource = dt;
                UnDoBeforeOrAfter(ref BackDataTable, ref AfterDataTable, flag);    //如果出栈的数据与gridOperatorTask.DataSource的数据相同,就递归调用函数
            }
            else
            {
                gridOperatorTask.DataSource = dt;
            }
        }


代码段四:DataTableEquals扩展函数的实现       

 图像示意

posted @ 2014-11-12 17:14  荣码一生  阅读(1749)  评论(3编辑  收藏  举报