WinForm 中如何使用后台线程来操作UI

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WinForm 中如何使用后台线程来操作UI相关的知识,希望对你有一定的参考价值。

参考技术A .net 2005之后线程不允许直接操作UI,否则会报错,但是可以用委托的方式来解决。
比如下面的datareflash是线程里的一个方法,它需要刷新页面控件的数据,那么就可以定义一个委托来实现,参考大妈如下:
public void DataReflash(string text)

if (text == "901")

MyInvoke mi = new MyInvoke(BindDate);//把BindDate的方法放在委托里边就行了,类似于你的SetText方法,这个方法里边写什么代码都行,如给文本框赋值,或重新绑定datagrid的数据源等
this.BeginInvoke(mi);

参考技术B 用委托,
或者在前台UI加一句
CheckForIllegalCrossThreadCalls = false;//不捕获对错误线程的调用

前者比较实用,后者治标不治本,不过都可以实现效果
参考技术C 需要使用委托

Winform实现多线程异步更新UI(进度及状态信息)

引言

在进行Winform程序开发需要进行大量的数据的读写操作的时候,往往会需要一定的时间,然在这个时间段里面,界面ui得不到更新,导致在用户看来界面处于假死的状态,造成了不好的用户体验。所以在大量数据操作的应用上,需要使用多线程来处理这种情况。在c#中使用多线程很方便只需要使用System.Threading.Thread的一个实例的Start方法就行了,但是如何实现多线程之间的交互就不是那么简单。本文实现了用子线程去处理数据,并实时更新主线程的ui状态了。下面就开始一步步的去实现异步线程更新ui的demo程序吧。

应用背景 


写入一定量的数据到文本文件中,同时需要在主界面中反应出写入数据的实时进度情况。要求:需要将写入数据封装成一个类。

实现过程


1、首先建立一个winform项目,在主窗体上拖入一个button,一个progressbar,一个lable。如下图所示。

 
2、编写一个处理数据的类(WriteDate),源代码如下。
publicclass DataWrite
    {
        publicdelegatevoid UpdateUI(int step);//声明一个更新主线程的委托public UpdateUI UpdateUIDelegate;

        publicdelegatevoid AccomplishTask();//声明一个在完成任务时通知主线程的委托public AccomplishTask TaskCallBack;
       
        publicvoid Write(object lineCount)
        {
            StreamWriter writeIO = new StreamWriter("text.txt", false, Encoding.GetEncoding("gb2312"));
            string head = "编号,省,市";
            writeIO.Write(head);
            for (int i = 0; i < (int)lineCount; i++)
            {
                writeIO.WriteLine(i.ToString() + ",湖南,衡阳");
                //写入一条数据,调用更新主线程ui状态的委托
                UpdateUIDelegate(1);
            }
            //任务完成时通知主线程作出相应的处理            TaskCallBack();
            writeIO.Close();
        }
    }

 

3、主界面中的代码如下:
  首先要建立一个委托来实现非创建控件的线程更新控件。 
delegatevoid AsynUpdateUI(int step);

 

   然后编写多线程去启动写入数据的方法以及回调的函数。
privatevoid btnWrite_Click(object sender, EventArgs e)
        {
            int taskCount = 10000; //任务量为10000this.pgbWrite.Maximum = taskCount;
            this.pgbWrite.Value = 0;

            DataWrite dataWrite = new DataWrite();//实例化一个写入数据的类
            dataWrite.UpdateUIDelegate += UpdataUIStatus;//绑定更新任务状态的委托
            dataWrite.TaskCallBack += Accomplish;//绑定完成任务要调用的委托
            Thread thread = new Thread(new ParameterizedThreadStart(dataWrite.Write));
            thread.IsBackground = true;
            thread.Start(taskCount);
        }

        //更新UIprivatevoid UpdataUIStatus(int step)
        {
            if (InvokeRequired)
            {
                this.Invoke(new AsynUpdateUI(delegate(int s)
                {
                    this.pgbWrite.Value += s;
                    this.lblWriteStatus.Text = this.pgbWrite.Value.ToString() + "/" + this.pgbWrite.Maximum.ToString();
                }), step);
            }
            else
            {
                this.pgbWrite.Value += step;
                this.lblWriteStatus.Text = this.pgbWrite.Value.ToString() + "/" + this.pgbWrite.Maximum.ToString();
            }
        }

        //完成任务时需要调用privatevoid Accomplish()
        {
            //还可以进行其他的一些完任务完成之后的逻辑处理
            MessageBox.Show("任务完成");
        }
效果如下:
总结

实现异步更新ui有很多种方法,但是我认为这种方式是比较灵活,能实时的获取到任务进行的状态,并且对之进行相应的处理。这种模式还适用于使用多个线程同时写入不同的数据到不同的文件中去。
源代码下载地址:http://download.csdn.net/detail/mingge38/9378852

以上是关于WinForm 中如何使用后台线程来操作UI的主要内容,如果未能解决你的问题,请参考以下文章

winform中如何在多线程中更新UI控件--ListView实时显示执行信息

Winform实现多线程异步更新UI(进度及状态信息)

C# SkiaSharp OpenTK Winform - 如何从后台线程中绘制?

如何在 WinForm 组件的 UI 线程上调用?

如何使后台工作线程之间的事件在自己的上下文中执行

winform 后台线程更新UI