2.<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />案例学习:CheckedListBox 控件设计开发的错误更正

1 )在第 1 部分中的开发后,运行时候主要的两个问题一个是必须点击星期信息两次才可以选中,另一个是当选择多项信息后,左侧信息无法移除干净,如图 2-38 所示的样子。

2-38  CheckedListBox移动后产生逻辑错误
2 )分析错误产生的主要原因是在删除左侧勾选信息的时候出错,此行问题代码如图 2-39 所示,并用鼠标左键点击该行代码处准备调试。

2-39  确定代码可能出现问题处
3 )运行程序,勾选左侧若干星期内容,点击右移动按钮,程序将在标注点停下,再按 F11 键进行单步调试。比如我们勾选了周一到周四连续四天项目,由于在循环体内每次凡是发现被勾选的项目都被用 remove 方法移除,导致循环条件( for (int i = 0; i < checkedListBox1.Items.Count; i++) )在每次循环后都逐渐减少,这将意味着每次循环的终止条件都是变动的,一旦剩余的被勾选的数目和循环次数相等,则循环立即结束,而不管是否还有剩余的被勾选项目没有被删除。

另外一个出错原因是,循环体内部的 if 条件语句,见下:

//问题1:循环的终止条件始终变动

for (int i = 0; i < checkedListBox1.Items.Count; i++)

    {//问题2:循环内部If条件语句出现问题

     if (checkedListBox1.CheckedItems.Contains(checkedListBox1.Items[i]))

        {

          checkedListBox3.Items.Add(checkedListBox1.Items[i].ToString() + "被移至右侧");

          checkedListBox1.Items.Remove(checkedListBox1.Items[i]);

        }

        }

该条 if 语句的意思是,如果发现被勾选的项目集合内,存在有第 i 行的 checkedListBox 行信息,则执行括号内的程序体。但是由于括号内的程序体本身执行 Remove 方法,会将已勾选项目从 checkedListBox 行信息中去除,将导致 checkedListBox 行信息的原有序列减少,而循环的检索依然按照 i 值本身的整数序列进行检索,导致检索行信息出现紊乱。

4 )代码更正:

在上述的循环体内,更正循环顺序,由递增循环改为递减循环,并由于这种改变使得每次的循环终止逻辑条件由动态变化,改为静态常量,从而改变由于减少列表行信息而引发的循环条件变化问题。更正后的代码见下(由右向左移动道理相同):

        private void button1_Click(object sender, EventArgs e)

        {

            foreach (object o in checkedListBox1.CheckedItems)

            {

                checkedListBox2.Items.Add(o);

            }

            for (int i = checkedListBox1.Items.Count - 1; i >= 0; i- -)

            {

                if (checkedListBox1.CheckedItems.Contains(checkedListBox1.Items[i]))

                {

                 checkedListBox3.Items.Add(checkedListBox1.Items[i].ToString() + "被移至左侧");

                 checkedListBox1.Items.Remove(checkedListBox1.Items[i]);

                }

            }

        }

3.

 

 

 

 

 

3.案例学习:CheckedListBox 控件设计开发的另一种解决方案

1)问题分析

解决信息移动的问题,最直接的想法是建立中间态的缓冲区,将左侧勾选的数据先行在该缓冲区中缓存,然后再删除左侧勾选信息,并将缓冲区的数据防止到左侧列表中即可完成任务。当然,这个缓冲区可以是列表,数组,队列等概念。此次我们通过数组 + 列表的方式实现上述的基本思想。首先建立两个数组和两个列表,通过确定勾选内容将最终未勾选的左侧数据赋值给左侧数组,已勾选的内容赋值给右侧数组,并最终将数组中真实的信息再次显示在左右列表内的办法实现基本算法。算法的基本思路见图 2-40 所示流程。

2-40  CheckedListBox移动后产生逻辑错误
2)下面将该部分算法代码描述如下(由右向左移动道理相同):

public partial class Form4 : Form

    {

        //建立数组,用以存储星期数据

        private string[] weekleft;

        private string[] weekright;

        //左右键点击次数

        int LeftClicknum = 0;

        int RightClicknum = 0;

        public Form4()

        {

            InitializeComponent();

        }

        /// <summary>

        /// 初始化事件在左侧的checkedListBox加载星期信息

        /// </summary>

        private void Form4_Load(object sender, EventArgs e)

        {

            checkedListBox1.Items.Add("星期一");

            checkedListBox1.Items.Add("星期二");

            checkedListBox1.Items.Add("星期三");

            checkedListBox1.Items.Add("星期四");

            checkedListBox1.Items.Add("星期五");

            checkedListBox1.Items.Add("星期六");

            checkedListBox1.Items.Add("星期日");

            //注意:下面内容是初始化时候,首先填充满左侧的数组weekleft[]

            weekleft = new string[checkedListBox1.Items.Count];

            for (int i = 0; i < weekleft.Length; i++)

            {

                weekleft[i] = checkedListBox1.Items[i].ToString();

            }

            //通过设置checkedListBox的CheckOnClick为true,可以使得单选一次既可以勾选一行信息。

            checkedListBox1.CheckOnClick = true;

            checkedListBox2.CheckOnClick = true;

            checkedListBox3.CheckOnClick = true;

        }

        /// <summary>

        /// 移至右侧部分项

        /// </summary>

        private void button1_Click(object sender, EventArgs e)

        {

            //建立两个列表,分别保存左右的勾选信息

            List<string> ListLeft = new List<string>();

            List<string> ListRight = new List<string>();

            //通过for循环,遍历左侧行信息

            for (int i = 0; i < checkedListBox1.Items.Count; i++)

            {

                //如果左侧第i行信息包含在勾选的集合之内

                if (checkedListBox1.CheckedItems.Contains(checkedListBox1.Items[i]))

                {

                   Array.Clear(weekleft, i, 1);

    //表示从左侧weekleft数组中清除第i个值,向后1位。目的是将已经填充满的左侧数组信息开始减少。

                   ListRight.Add(checkedListBox1.Items[i].ToString());

                   //将移除的项目添加到临时列表ListRight,代表右侧列表。

                }

            }

            //判断左侧是否是第一次点击;

            if (LeftClicknum == 0)

            {

                //如果是则将右侧列表转换成为数组后赋值给右侧数组weekright[]

                weekright = ListRight.ToArray();

                //左侧点击次数累加1

                LeftClicknum++;

            }

            else

            {

                //如果不是第一次点击,根据右侧checkedListBox内已经填充的个数进行循环

                for (int i = 0; i < checkedListBox2.Items.Count; i++)

                {

                    ListRight.Add(checkedListBox2.Items[i].ToString());

                    //先把右侧已经添加的行信息注入到右侧列表ListRight内

                }

                weekright = ListRight.ToArray();

                //然后将右侧列表ListRight转换成为数组后赋值给右侧数组weekright[]

            }

            //建立列表缓冲保存

            foreach (string s in weekleft)

            {

                if (!string.IsNullOrEmpty(s)) ListLeft.Add(s);//遍历左侧数组,添加左侧列表

            }

            weekleft = ListLeft.ToArray();

            //将左侧列表转化成为数组后再复制给左侧数组。

            //注意:由于C#中没有动态数组的概念,因此采取这样的方式改变数组的长度和内容。

            checkedListBox1.Items.Clear();

            checkedListBox2.Items.Clear();

            //将左右两侧的checkedListBox全部清空,准备将数组信息开始填充

            for (int i = 0; i < weekleft.Length; i++)

            {

                checkedListBox1.Items.Add(weekleft[i].ToString());

            }

            for (int j = 0; j < weekright.Length; j++)

            {

                checkedListBox2.Items.Add(weekright[j].ToString());

            }

        }

………