年终公司开年会,节目上有个抽奖节目,公司要求用程序随机抽取中奖者,因为抽奖者众多,我用了多线程来进行开发,我的大概思路是这样的:主界面上有5列,每列有13个Label存放待抽奖者,每个线程控制一列,当按下开始按钮时,5个线程同时启动,每个线程通过如下方法为Label赋值:
if (Thread.CurrentThread.ManagedThreadId == t2.ManagedThreadId)
            {                while (true)
                {
                    int z = 0;
                    Random a = new Random();
                    for (int i = 14; i <= 2 * 13; i++)
                    {
                        z = a.Next(200, 400);
                        ((Label)(panel2.Controls.Find("L" + i.ToString(), true)[0])).Text = GetStaff.arrStaff[z].ToString();
                    }                    Thread.Sleep(100);
                }
            }
这样一旦启动线程,Label上的名字就实现变换,当按下停止按钮的时候,线程终止,Label上的Text就是中奖者,但问题来了,在启动一个线程的时候,这个做法没问题,但在5个线程一起开的时候,运行时会报一个异常:集合在枚举数实例化后进行了修改.这句话什么意思??异常那句就是((Label)(panel2.Controls.Find("L" + i.ToString(), true)[0])).Text = GetStaff.arrStaff[z].ToString();
其中GetStaff类是用来读取员工名单的一个txt文件,类代码如下class GetStaff
    {
        public static string[] GetStaffInfo()
        {
            
            string[] staff = File.ReadAllLines(@"StaffSources.txt",Encoding.Default);
            return staff;
        }        public static ArrayList arrStaff = new ArrayList(GetStaffInfo());
    }
请问是什么原因导致异常?急求解决办法!谢谢

解决方案 »

  1.   

    foreach遍历时,进行了修改,将foreach改成for 
    foreach   语句用于循环访问集合以获取所需信息,但不应用于更改集合内容以避免产生不可预知的副作用。 
     
      

  2.   

    public static ArrayList arrStaff = new ArrayList(GetStaffInfo());是因为上句中的静态变量arrStaff 被不同线程修改所致,因为静态变量是全局的,当一个线程正在使用时,其他线程对她进行了修改,所以导致报错,你应该进行线程同步,或者没一个线程单独使用一个ArrayList 类型变量
      

  3.   

    1楼的,你看清楚,我没有用到foreach,不要在网上随便找一个回答复制粘贴,2楼的,我虽然有5个线程同时调用arrStaff,但是我并没有对她进行过修改啊!!
      

  4.   

    出问题时候,点详细,可以看到具体问题。
    少用panel2.Controls.Find的方法,自己记录下来,例如
    Label[] lbs = new Label[]{Label1,Label2   等};
    使用这个lbs数组。
      

  5.   

    你好,5楼的仁兄,现在问题似乎不是在Find方法上,我觉得2楼的仁兄说得有点道理,但是我很纳闷,线程里面根本没有修改过arrStaff的值呢
      

  6.   

    “抽奖者众多”并不是使用多线程的理由((Label)(panel2.Controls.Find("L" + i.ToString(), true)[0])).Text = GetStaff.arrStaff[z].ToString();这句拆开几句写,先搞清楚是哪个集合出了问题
      

  7.   

    嗯,panel2.Controls在报错时里面居然有130个Label,但是我在panel2里面只放了65个,为什么会多了一倍呢???
      

  8.   

    8楼的,你好,因为抽奖者名额多,用单一线程给65个Label赋值会很慢的,所以采用了多线程,一个线程控制13个label的变化
      

  9.   

    具体报错原因是:“panel2.Text”引发了“Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException”类型的异常
      

  10.   

    所以了,问题描述清晰点吗。你按我说的,用一个数组缓存是对的。或是你Invoke一下。
    this.Invoke((EventHandler)delegate
    {
        ((Label)(panel2.Controls.Find("L" + i.ToString(), true)[0])).Text = GetStaff.arrStaff[z].ToString();
    });
      

  11.   

    额,是没有报错了,但是显示却有点问题,有些Label不能正常显示出名字!
      

  12.   

    是不是Invoke调用的位置不正确
      

  13.   

    UI跨线程调用的问题还在苦苦刷新页面等待回复吗?用《Csdn收音机》告别烦恼!
      

  14.   

    这个是因为 UI 对象不能在创建它的线程(主线程)之外修改吧?
    12 楼用 this.Invoke 正是把具体的处理又丢回 UI 线程了
      

  15.   


    所有对控件的操作最终都要在 UI 线程上完成,你用了多线程,就不得不测试 InvokeRequired 属性,然后使用 Invoke 来执行委托。动画效果本来就不是 winform 的长处。试试 DoubleBuffered。
      

  16.   

    控件或窗体.Invoke((EventHandler)delegate
    {
        //操作界面
    });
    也可使用BackGroundWorker
    ThreadPool.QueueUserWorkItem
      

  17.   

    似乎Find方法内部用的是foreach实现。
      

  18.   

    谢谢各位热心的回答,CSDN果然高手众多!问题已经解决了,KissXYL的方法是对的!UI界面显示不太正确是因为线程太多,而我的配置又不是很高(笔记本,thinkpad x60,6年前的机子,^_^)所以文字看起来变动比较慢,并且有字影残留.再次谢谢各位热心人士,22楼wuyq11的回答也正确,但因为是KissXYL先回答的,所以分数都给你了!