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;
            }
        }
时间: 2024-10-22 04:56:29

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

(转).NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例

http://2sharings.com/2014/net-4-5-task-run-parallel-for-winform-cross-multiple-threads-update-ui-demo 在C# WINFORM的开发中,难免会遇到多线程的开发以提高程序的执行效率.自己刚才开始在做多线程的开发时也遇到了很多这方面的问题,比如:如何使用并实现多线程功能.跨线程更新UI控件等问题.还记得最初使用的是System.Threading命名空间下的Thread类来实现的: C# 1 2 3

C# Winform 跨线程更新UI控件常用方法总结(转)

出处:http://www.tuicool.com/articles/FNzURb 概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种: 1. 通过UI线程的SynchronizationContext的Post/Send方法更新: 2. 通过UI控件的Invoke/BegainInvoke方法更新: 3. 通过BackgroundWorker取代Thre

C# Winform 跨线程更新UI控件常用方法汇总

C# Winform 跨线程更新UI控件常用方法汇总 概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种:1. 通过UI线程的SynchronizationContext的Post/Send方法更新:2. 通过UI控件的Invoke/BeginInvoke方法更新: 3. 通过BackgroundWorker取代Thread执行异步操作:4. 通过设置窗体

理解SynchronizationContext,如何在Winform里面跨线程访问UI控件

SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文. 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为.此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求.同步模型的提供程序可以扩展此类并为这些方法提供自己的实现.(来自MSDN)简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色.另外这里有个地方需要清楚的,不是每个线

实现Winform 跨线程安全访问UI控件

在多线程操作WinForm窗体上的控件时,出现"线程间操作无效:从不是创建控件XXXX的线程访问它",那是因为默认情况下,在Windows应用程序中,.NET Framework不允许在一个线程中直接操作另一个线程中的控件(因为访问Windows窗体控件本质上不是线程安全的).微软为了线程安全,窗体上的控件只能通过创建控件的线程来操作控件的数据,也就是只能是UI线程来操作窗体上的控件!可看看Control的Invoke和BeginInvoke 要解决这个问题可以用以下方法: 1.关闭线

C# winform窗体假死

C#  winform窗体假死 我们经常会遇到当执行一个比较大的函数时,窗体会出现假死的现象,给用户的体验不是很好,于是我们遇到了问题,那么就必须解决,我们该如何解决呢,首先在自己的脑里画个问号,接下来我们就一起研究吧! 先分析,这个问题是如何出现的呢!为什么会出现,如何避免出现,避免不了的,如何解决等,下面我们就去解决问题吧,遇到问题不要怕,解决问题是我们成长最快的时候,曾经别人告诉我,不怕不会做,就怕想不到.那我们就进入正题吧! 窗体假死是如何出现的呢? 在调用    testc();函数时

C# 解决窗体假死的状态

异步调用是CLR为开发者提供的一种重要的编程手段,它也是构建高性能.可伸缩应用程序的关键.在多核CPU越来越普及的今天,异步编程允许使用非常少的线程执行很多操作.我们通常使用异步完成许多计算型.IO型的复杂.耗时操作,去取得我们的应用程序运行所需要的一部分数据.在取得这些数据后,我们需要将它们绑定在UI中呈现.当数据量偏大时,我们会发现窗体变成了空白面板.此时如果用鼠标点击,窗体标题将会出现”失去响应”的字样,而实际上UI线程仍在工作着,这对用户来说是一种极度糟糕的体验.如果你希望了解其中的原因

谈.Net委托与线程——解决窗体假死

引言 在之前的<创建无阻塞的异步调用>中,已经介绍过异步调用的编写步骤和实施原理.异步调用是CLR为开发者提供的一种重要的编程手段,它也是构建高性能.可伸缩应用程序的关键.在多核CPU越来越普及的今天,异步编程允许使用非常少的线程执行很多操作.我们通常使用异步完成许多计算型.IO型的复杂.耗时操作,去取得我们的应用程序运行所需要的一部分数据.在取得这些数据后,我们需要将它们绑定在UI中呈现.当数据量偏大时,我们会发现窗体变成了空白面板.此时如果用鼠标点击,窗体标题将会出现"失去响应&

C# 委托 线程 窗体假死

转载:http://www.cnblogs.com/smartls/archive/2011/04/08/2008981.html 异步调用是CLR为开发者提供的一种重要的编程手段,它也是构建高性能.可伸缩应用程序的关键.在多核CPU越来越普及的今天,异步编程允许使用非常少的线程执行很多操作.我们通常使用异步完成许多计算型.IO型的复杂.耗时操作,去取得我们的应用程序运行所需要的一部分数据.在取得这些数据后,我们需要将它们绑定在UI中呈现.当数据量偏大时,我们会发现窗体变成了空白面板.此时如果用