winform 利用 多线程 处理窗体假死,利用 Invoke BeginInvoke 处理子线程调用 UI 控件报错的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了winform 利用 多线程 处理窗体假死,利用 Invoke BeginInvoke 处理子线程调用 UI 控件报错的问题相关的知识,希望对你有一定的参考价值。

因为工作需要自己写了一个简单的工具软件,数据库查询每日OA未发送成功流程的日志记录以及批量重处理操作。

技术分享

开始使用的是单线程,后台查询数据库的时候窗体假死,使用多线程很简单就能解决。

        private void btnQuey_Click(object sender, EventArgs e)
        {
            this.button2.Enabled = false;
            Thread connectionThread = new Thread(new ThreadStart(connectDB));
            connectionThread.Start();
        }

接下来的问题就比较棘手,因为我在子线程中会调用UI控件,这个时候多次点击查询(调用子线程)就会报错,刚遇见的时候真的没有思路,后来网上无意中看到一篇文章写Invoke和BeginInvoke的(http://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html),文章很好,而且恰好就能解决我的问题。原来是windows程序消息机制的问题,子线程如果直接调用UI控件就会影响这个机制。

 

delCheckEnvironment委托是用来检查查询环境是否选择,如果选择了才能继续往下执行子线程,有先后关系,所以使用Invoke把delCheckEnvironment封送到主线程执行,阻塞子线程往下执行,直到封送的委托被主线程执行完毕。
而下面的BeginInvoke(delUpdateGridView,ds)就不需要阻塞子线程,让主线程的GridView显示数据集的时候子线程也执行,不需要区分先后顺序。


 

 

        private void connectDB()
        {

            DelCheckEnvironment delCheckEnvironment = new DelCheckEnvironment(CheckEnvironment);
            
            Invoke(delCheckEnvironment);

            DateTime startTime = this.dateTimePicker1.Value;
            DateTime endTime = this.dateTimePicker2.Value;

            string st = startTime.ToString("yyyy-MM-dd 00:00:00 000");
            string st1 = (startTime + TimeSpan.FromDays(1)).ToString("yyyy-MM-dd 00:00:00 000");
            string ed = endTime.ToString("yyyy-MM-dd 00:00:00 000");
            string ed1 = (endTime + TimeSpan.FromDays(1)).ToString("yyyy-MM-dd 00:00:00 000");
            string sql = "select distinct SendDH,Taskid,Returnmsg from AYS_Process_Log where SendTime >=‘" + st + "‘ and SendTime <‘" + st1 + "‘ and Returnmsg not like ‘%成功%‘ and Returnmsg not like  ‘%已接收%‘ and Returnmsg not like ‘%{\\"data\\":{},\\"returncode\\":\\"0\\"}%‘  and Returnmsg <> ‘‘ and Returnmsg not like ‘%\\"ZSTS\\":1%‘ and Returnmsg not like ‘%OA单号在SAP系统内已存在%‘ and Taskid not in "
                         + "(select distinct Taskid from Process_Log where (SendTime >=‘" + st + "‘ and SendTime <‘" + ed1 + "‘) and(Returnmsg like ‘%成功%‘ or Returnmsg like  ‘%已接收%‘ or Returnmsg like ‘%{\\"data\\":{},\\"returncode\\":\\"0\\"}%‘  or Returnmsg = ‘‘ or Returnmsg like ‘%\\"ZSTS\\":1%‘ or Returnmsg like ‘%OA单号在SAP系统内已存在%‘))";

            DataSet ds = new DataSet();
            try
            {
                using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[sqlIp].ConnectionString.ToString()))
                {
                    using (SqlCommand cmd = new SqlCommand(sql, conn))
                    {
                        cmd.CommandTimeout = 80000;
                        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                        {
                            da.Fill(ds, "Process_Log");
                        }
                    }
                }
            DelUpdateGridView delUpdateGridView = new DelUpdateGridView(updateGridView);
            BeginInvoke(delUpdateGridView,ds);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            
        }
        private void updateGridView(DataSet ds)
        {
            if (ds.Tables[0].Rows.Count > 0)
            {
                this.dataGridView1.DataSource = ds;
                this.dataGridView1.DataMember = "AYS_Process_Log";
                dataGridView1.Columns[0].HeaderText = "OA单号";
                dataGridView1.Columns[0].Width = 120;
                dataGridView1.Columns[1].HeaderText = "TaskId";
                dataGridView1.Columns[1].Width = 50;
                dataGridView1.Columns[2].HeaderText = "接口返回信息";
                dataGridView1.Columns[2].Width = 1000;
            }
            else
            {
                MessageBox.Show("未查询到失败单号");
            }
            this.btnQuery.Enabled = true;
        }

        public void CheckEnvironment()
        {
            if (checkEnviroment())
            {
                MessageBox.Show("请选择环境");
                this.btnQuery.Enabled = true;
                return;
            }
        }

 




以上是关于winform 利用 多线程 处理窗体假死,利用 Invoke BeginInvoke 处理子线程调用 UI 控件报错的问题的主要内容,如果未能解决你的问题,请参考以下文章

wpf中 我新开一个线程添加控件到主窗体

c#winform多线程

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

c#中我要实现大量的httpwebrequest,但是不想winform假死住,请问用多线程还是异步?

C#多线程实现循环。界面会假死怎么办?

WinForm 多线程+委托来防止界面假死