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 控件报错的问题的主要内容,如果未能解决你的问题,请参考以下文章
c#winform 多线程绑定datagridview会造成假死,滚动条无法滚动,用委托怎么做