C#实现的简易含undoredo功能的winForm
本次实验在第三次的基础上加上了undo/redo功能,主要⽤了undo栈和redo栈保存状态的变化,⽽对于全局控件的变化采⽤⼀个state类的对象来保存各个控件的属性。每次操作进undo栈,点击undo的时候弹出栈顶元素并进⼊redo栈,取此时的栈顶元素(因为最初栈顶的元素是当前的状态,⽽undo要撤销到上⼀状态)将当前状态置为该状态。Redo的时候从redo栈顶取出undo是压⼊栈的元素,将当前状态置为该状态。实现思路是这样,但是实现过程中也遇到了许多问题,如下:
1、监听了状态变化,并把变化的操作⼊栈,但是undo/redo的时候也会影响状态的变化,⽽此时状态的变化是不应该进栈的。所以设置了标记变量,判断当前状态的变化是否是undo/redo导致的,只有是⽤户主动改变状态的时候才应该进栈。
2、设计数据结构的时候没有考虑到listBox的状态,当前选中的可能是多选,⽆法⽤String类型来保存属性。但只有这个是特殊的,没有必要修改数据结构,所以采⽤了字符串拼接的⽅式,对每次选中的index⽤分隔符分割并保存为字符串
String tmp = "";
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;
public String username
{
get{ return _username; }
set{ _username = value; }            }
public String pwd
{
get{ return _pwd; }
set{ _pwd = value; }
}
public String 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; }
}
public String listbox
{
get{ return _listbox; }
set{ _listbox = value; }
}
}
每次进栈的操作,使⽤属性对成员变量操作。由于对⼀个控件来说操作是确定的,所以使⽤⼀个String类型的value来保存属性,String类型的name来保存控件的名称,可以通过名称到该控件。Type属性是int类型,代码中有注释,为了区分不同类型的控件,将通过名称到的控件强制转化为真实的类型。
class item
{
private String _Name;
public String Name
{
get{ return _Name; }
set{ _Name = value; }
}
//0textbox  1 radiobutton  2 checkbox  3 combobox  4 date  5 listbox  6 button  7 tag
private Int32 _Type;
public Int32 Type
{
get{ return _Type; }
set{ _Type = value; }
}
private String _Value;
public String Value
{
get{ return _Value; }
set{ _Value = value; }
}
public item(String name, Int32type, String value)
{
this._Name= name;
this._Type= type;
this._Value= value;
}
}
程序使⽤简要说明:
默认undo次数为10,可以进⾏设置,点击“参数设置”才会⽣效。Undo/redo达到指定次数,或者回退到最早的状态会灰⾊,不可点击。基本信息的三个⽂本框都⽀持单个字符和焦点的变化。标签是根据listBox的选择⽽改变的,undo/redo是对listBox 选择的操作。按钮的点击并⽆实际功能,除了重置键之外,其他的状态保存为焦点的变化。
界⾯截图如下:
附上完整的后台代码,就⼀个winform的窗体:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace _3
{
public partial class form : Form
{
class State
{
String _username;
String _pwd;
String _pwd2;
bool _check1;
bool _check2;
bool _check3;
String _listbox;
public String username
{
get { return _username; }
set { _username = value; }
}
public String pwd
{
get { return _pwd; }
set { _pwd = value; }
}
public String pwd2
{
get { return _pwd2; }
set { _pwd2 = value; }
}
public bool check1
{
get { return _check1; }
set { _check1 = value; }
}
public bool check2
{
get { return _check2; }
set { _check2 = value; }
}
public bool check3
{
{
get { return _check3; }
set { _check3 = value; }
}
public String listbox
{
get { return _listbox; }
set { _listbox = value; }
}
}
class item
{
private String _Name;
public String Name
{
get { return _Name; }
set { _Name = value; }
}
//0 textbox  1 radiobutton  2 checkbox  3 combobox  4 date  5 listbox  6 button  7 tag            private Int32 _Type;
public Int32 Type
{
get { return _Type; }
set { _Type = value; }
}
private String _Value;
public String Value
{
get { return _Value; }
set { _Value = value; }
}
public item(String name, Int32 type, String value)
{
writeline方法的作用this._Name = name;
this._Type = type;
this._Value = value;
}
}
Stack<item> undoStack = null;
Stack<item> redoStack = null;
State state = null;
Int32 number = 10;
bool flag = false;//判断上次是否是undo/redo操作界⾯的操作
bool listbox_flag = true; //判断listbox,使selectValueChanged只触发⼀次
public form()
{
InitializeComponent();
//comboBox1.SelectedIndex = 0;
//username.Focus();
state = new State();
ToolTip tt_uname = new ToolTip();
ToolTip tt_pwd = new ToolTip();
ToolTip tt_pwd2 = new ToolTip();
ToolTip tt_tag = new ToolTip();
ToolTip tt_register = new ToolTip();
ToolTip tt_reset = new ToolTip();
ToolTip tt_exit = new ToolTip();
tt_uname.IsBalloon = true;
tt_pwd.IsBalloon = true;
tt_pwd2.IsBalloon = true;
tt_tag.IsBalloon = true;
tt_exit.IsBalloon = true;
tt_register.IsBalloon = true;
tt_exit.IsBalloon = true;
tt_reset.IsBalloon = true;
tt_exit.ist, "退出程序");

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。