跨线程操作UI控件

写程序的时候经常会遇到跨线程访问控件的问题,看到不少人去设置Control.CheckForIllegalCrossThreadCalls = false;这句话是告诉编译器不要对跨线程访问作检查,可以实现访问,但是出不出错就不一定了。

个人建议使用委托delegate来实现。Windows中,UI是单线程的,即不允许多个线程直接访问它,通常它只由创建这个控件的线程(主线程)来控制,所以可以通过委托,告诉主线程对控件进行操作。

点击一个按钮,就创建一个线程添加一个item到ListView中,直接操作如下:

//添加item
private
void AddItems() { this.listView1.Items.Add(new ListViewItem(new string[]{ Thread.CurrentThread.ManagedThreadId.ToString(), DateTime.Now.ToLongTimeString() })); }

按钮事件

 private void button1_Click(object sender,EventArgs e)
       {
           Thread back_thread = new Thread(new ThreadStart(AddItems));
           back_thread.Start();
       }

运行,点击按钮,产生以下异常

 

修改方式

声明一个委托

private delegate void addItemHandler(string ThreadID);

声明一个RunBackThread方法,它负责告诉主线程要干什么

private void RunBackThread()
       {
           if (this.listView1.InvokeRequired)
           {
//声明一个AddItems的委托 addItemHandler add
= new addItemHandler(AddItems);
//this.Invoke(委托,请求线程ID参数)
this.Invoke(add,new object[]{Thread.CurrentThread.ManagedThreadId.ToString()}); } }
this.Invoke的意思是在主线程上执行指定的委托,还有this.BeginInvoke在主线程上异步执行指定的委托。

按钮事件
private void button1_Click(object sender,EventArgs e)
       {
           Thread back_thread = new Thread(new ThreadStart(RunBackThread));
           back_thread.Start();
       }
AddItems方法和原来一样
private void AddItems(string ThreadID)
       {
           this.listView1.Items.Add(new ListViewItem(new string[]{
               ThreadID,//请求线程ID
Thread.CurrentThread.ManagedThreadId.ToString(),//主线程ID DateTime.Now.ToLongTimeString() })); }

这里之所以通过string ThreadID来获取请求线程id是因为AddItems这个方法是由主线程执行的,所以在AddItems方法里面通过Thread.CurrentThread.ManagedThreadId获取的id都是主线程id。

执行结果

这个图看起来应该很容易明白了吧。



posted @ 2014-04-18 18:13  快看一只熊  阅读(470)  评论(0编辑  收藏  举报