C#Invoke委托在多线程中的使用

Posted 无声蝉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#Invoke委托在多线程中的使用相关的知识,希望对你有一定的参考价值。

一步一步跟随着我的脚步看一看

Form上我设置一个button,text属性为“点击开始测试”;现在我想点击它以后,动态变化从1~10赋值

(1)

第一个映入脑中的方式就是这样写

private void button1_Click(object sender, EventArgs e)

    button1.Enabled = false;
    for(int i=1;i<10;i++)
    
        button1.Text = i.ToString();
        Thread.Sleep(1000);
    
    button1.Text = "点击开始测试";
    button1.Enabled = true;

有没有问题?肯定有的啦,我点击以后,界面倒是disable了,但是没有1~10出现,时间一到,恢复enable。为什么呢?

原因:直接主线程休眠是达不到效果的,此时桌面还处于假死状态,更新不了text值。代码放在了UI线程执行,阻塞了UI的显示,所以中间的结果你看不到。实验了两种方式解决:

  1. 在Thread.Sleep(1000);后加 button1.Refresh();
  2. 在Thread.Sleep(1000);后加 Application.DoEvents();

(2)

既然是由于代码放在了UI线程,那我新建个线程,在那里面更新UI控件好了。

private void button1_Click(object sender, EventArgs e)

    //启动一个线程
    new Thread(ThreadTask).Start();

//线程函数
public void ThreadTask()

    button1.Enabled = false;
    for (int i = 0; i < 10; i++)
    
        button1.Text = i.ToString();
        Thread.Sleep(1000);
    
    button1.Text = "点击开始测试";
    button1.Enabled = true;

出错了!!!

造成这种异常的原因在于,控件是在主线程中创建的(比如this.Controls.Add(...);),进入控件的事件响应函数时,是在控件所在的线程,并不是主线程。在控件的事件响应函数中改变控件的状态,可能与主线程发生线程冲突。如果主线程正在重绘控件外观,此时在别的线程改变控件外观,就会造成画面混乱。

(3)

下面该主角出场了,C#的委托机制,由于历史的原因,有这么几种形式:

//第一种
button1.Invoke(new EventHandler(delegatebutton1.Text = "关闭";));
//第二种
this.Invoke(new EventHandler(delegatebutton1.Text = "关闭";));
//第三种 网上说自C# 3.0开始就有了
this.Invoke(new Action(() => button1.Text = "关闭";));

我喜欢用第三种,好记,哈哈。好了,接下来实现以下吧!

private void button1_Click(object sender, EventArgs e)
         
    //启动一个线程
    new Thread(ThreadTask).Start();

        //线程函数
public void ThreadTask()

    //首先将button对象禁用
    this.Invoke(new Action(() =>
    
        button1.Enabled = false;
    ));
    for (int i = 0; i < 10; i++)
    
        this.Invoke(new Action(() =>
        
            button1.Text = i.ToString();
        ));
        Thread.Sleep(1000);
    
    //虽然不是循环内,请不要忘记,你的调用依然在辅助线程中,所以,还是需要invoke的。
    //还原状态,设置按钮的文本为初始状态,设置按钮可用。
    this.Invoke(new Action(() =>
    
        button1.Text = "点击开始测试";
        button1.Enabled = true;
    ));

    

大功告成喽!!

 

以上是关于C#Invoke委托在多线程中的使用的主要内容,如果未能解决你的问题,请参考以下文章

在多线程应用程序中使用带有媒体基础接口的 P/Invoke 发生 AccessViolationException

C# this.Invoke()的作用与用法

(转)c#多线程 Invoke方法的使用

多线程UI

C# invoke使用

c#winform 多线程绑定datagridview会造成假死,滚动条无法滚动,用委托怎么做