C#实现的简易含undo/redo功能的winForm

本次实验在第三次的基础上加上了undo/redo功能,主要用了undo栈和redo栈保存状态的变化,而对于全局控件的变化采用一个state类的对象来保存各个控件的属性。每次操作进undo栈,点击undo的时候弹出栈顶元素并进入redo栈,取此时的栈顶元素(因为最初栈顶的元素是当前的状态,而undo要撤销到上一状态)将当前状态置为该状态。Redo的时候从redo栈顶取出undo是压入栈的元素,将当前状态置为该状态。实现思路是这样,但是实现过程中也遇到了许多问题,如下:

1、 监听了状态变化,并把变化的操作入栈,但是undo/redo的时候也会影响状态的变化,而此时状态的变化是不应该进栈的。所以设置了标记变量,判断当前状态的变化是否是undo/redo导致的,只有是用户主动改变状态的时候才应该进栈。

2、 设计数据结构的时候没有考虑到listBox的状态,当前选中的可能是多选,无法用String类型来保存属性。但只有这个是特殊的,没有必要修改数据结构,所以采用了字符串拼接的方式,对每次选中的index用分隔符分割并保存为字符串

   Stringtmp = "";

           for(int i = 0; i <listBox1.SelectedIndices.Count; i++)

            {

                tmp +=(listBox1.SelectedIndices[i] +"#");

            }

恢复的时候再把该字符串解开,依次listBox的select赋值。

    string[] s= last.Value.Split(new char[]{ '#' });

                        listbox_flag =true;//必须在clear, setIndex的函数之前

                        ((ListBox)control).ClearSelected();

                       for(int i=0; i<s.Length-1; i++)

                        {

                           //MessageBox.Show(s[i]);

                            ((ListBox)control).SelectedIndex =Int32.Parse(s[i]);

                        }

                        listbox_flag =true;

3、关于listBox确实很麻烦,进行了大量的修改。之前把状态变化写在selectChange的函数里,undo/redo中每次给select赋值都会调用这个函数,而只有第一次能判断是点击了undo/redo,之后无法判断。后来改写在了click函数中,避免此类问题。


关键的数据结构:

保存全局的状态,后来增加的,为了全局的undo/redo,使用属性操作成员变量。

class State

        {

            String_username;

            String_pwd;

            String_pwd2;

            bool_check1;

            bool_check2;

            bool_check3;

            String_listbox;

            publicString username

            {

                get{ return _username; }

                set{ _username = value; }

            }

            publicString pwd

            {

                get{ return _pwd; }

                set{ _pwd = value; }

            }

            publicString pwd2

            {

                get{ return _pwd2; }

                set{ _pwd2 = value; }

            }

            publicbool check1

            {

                get{ return _check1; }

                set{ _check1 = value; }

            }

            publicbool check2

            {

                get{ return _check2; }

                set{ _check2 = value; }

            }

            publicbool check3

            {

                get{ return _check3; }

                set{ _check3 = value; }

            }

            publicString listbox

            {

                get{ return _listbox; }

                set{ _listbox = value; }

            }

        }

 

每次进栈的操作,使用属性对成员变量操作。由于对一个控件来说操作是确定的,所以使用一个String类型的value来保存属性,String类型的name来保存控件的名称,可以通过名称找到该控件。Type属性是int类型,代码中有注释,为了区分不同类型的控件,将通过名称找到的控件强制转化为真实的类型。

        class item

        {

            privateString _Name;

            publicString Name

            {

                get{ return _Name; }

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值