在C#中子线程如何操作主线程中窗体上控件
在C#中,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程是不同的空间,因此想要在子线程来操作窗体上的控件,是不可能 简单的通过控件对象名来操作,但不是说不能进行操作,微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的控件操作。
要实现该功能,基本思路如下:
把想对另一线程中的控件实施的操作放到一个函数中,然后使用delegate代理那个函数,并且在那个函数中加入一个判断,用 InvokeRequired 来判断调用这个函数的线程是否和控件线程处于同一线程中,如果是则直接执行对控件的操作,否则利用该控件的Invoke或BeginInvoke方法来执 行这个代理。示例代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Windows.Forms;
4
5 using System.Threading;
6
7 namespace 子线程操作主线程窗体上的控件
8 {
9 public partial class frmMain : Form
10 {
11 /********************** 定义该类的私有成员 **************************/
12
13 /// <summary>
14 /// 定义一个队列,用于记录用户创建的线程
15 /// 以便在窗体关闭的时候关闭所有用于创建的线程
16 /// </summary>
17 private List<Thread> ChaosThreadList;
18
19 /********************** 该类的初始化相关函数 ************************/
20
21 /// <summary>
22 /// 窗体的初始化函数,初始化线程队列ChaosThreadList
23 /// </summary>
24 public frmMain()
25 {
26 InitializeComponent();
27 ChaosThreadList = new List<Thread>();
28 }
29
30 /// <summary>
31 /// 窗体的关闭事件处理函数,在该事件中将之前创建的线程全部终止
32 /// </summary>
33 /// <param name="sender"></param>
34 /// <param name="e"></param>
35 private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
36 {
37 if (ChaosThreadList.Count > 0)
38 {
39 //编列自定义队列,将所有线程终止
40 foreach (Thread tWorkingThread in ChaosThreadList)
41 {
42 tWorkingThread.Abort();
43 }
44 }
45 }
46
47 /**************************** 定义该类的自定义函数 ***********************/
48
49 /// <summary>
50 /// 定义一个代理
51 /// </summary>
52 /// <param name="index"></param>
53 /// <param name="MSG"></param>
54 private delegate void DispMSGDelegate(int index,string MSG);
55
56 /// <summary>
57 /// 定义一个函数,用于向窗体上的ListView控件添加内容
58 /// </summary>
59 /// <param name="iIndex"></param>
60 /// <param name="strMsg"></param>
61 private void DispMsg(int iIndex,string strMsg)
62 {
63 if (this.lstMain.InvokeRequired==false) //如果调用该函数的线程和控件lstMain位于同一个线程内
64 {
65 //直接将内容添加到窗体的控件上
66 ListViewItem lvi = new ListViewItem();
67 lvi.SubItems[0].Text = iIndex.ToString();
68 lvi.SubItems.Add(strMsg);
69 this.lstMain.Items.Insert(0, lvi);
70 }
71 else //如果调用该函数的线程和控件lstMain不在同一个线程
72 {
73 //通过使用Invoke的方法,让子线程告诉窗体线程来完成相应的控件操作
74 DispMSGDelegate DMSGD = new DispMSGDelegate(DispMsg);
75
76 //使用控件lstMain的Invoke方法执行DMSGD代理(其类型是DispMSGDelegate)
77 this.lstMain.Invoke(DMSGD, iIndex, strMsg);
78
79 }
80 }
81
82 /// <summary>
83 /// 定义一个线程函数,用于循环向列表中添加数据
84 /// </summary>
85 private void Thread_DisplayMSG()
86 {
87 for (int i = 0; i < 10000; i++)
88 {
89 DispMsg(i + 1, "Welcome you : " + (i + 1).ToString());
90 Thread.Sleep(10);
91 }
92 }
93
94 /******************************* 定义该类的事件处理函数 ********************************/
95
96 /// <summary>
97 /// 【开始】按钮的单击事件处理函数,新建一个线程向窗体上的ListView控件填写内容
98 /// </summary>
99 /// <param name="sender"></param>
100 /// <param name="e"></param>
101 private void btnBegin_Click(object sender, EventArgs e)
102 {
103 //创建一个新的线程
104 Thread tWorkingThread = new Thread(Thread_DisplayMSG);
105
106 //将新建的线程加入到自定义线程队列中,以便在窗体结束时关闭所有的线程
107 ChaosThreadList.Add(tWorkingThread);
108
109 //开启线程
110 tWorkingThread.Start();
111 }
112
113 }
114 }
这样子就可以实现用子线程去操作主线程窗体上的控件的内容,同时,又不影响主线程对窗体上其他控件的响应。程序运行截图如下:
点击[开始]按钮,程序开启一个新的线程,不断向列表中添加新的数据,而同时不会影响主界面对其它控件(例如:文本框)的响应。
[P.S]:
INVOKE方法的作用:
它使该控件所在的线程执行Invoke方法参数中指定的代理,也就是使主线程执行我们想对控件进行的操作。
在C#中子线程如何操作主线程中窗体上控件的更多相关文章
- C#中子线程操作主线程中窗体上控件的方法
Demo this.listView1.Visible = true; this.listView1.BeginUpdate();this.listView1.EndUpdate(); //结束数据处 ...
- 用委托在listbox中异步显示信息,解决线程间操作无效,从不是创建控件的线程访问它
//创建一个委托,是为访问listbox控件服务的. public delegate void UpdateTxt(string msg); //定义一个委托变量 public UpdateTxt u ...
- [Winform]线程间操作无效,从不是创建控件的线程访问它的几个解决方案,async和await?
目录 概述 取消跨线程检查 使用委托异步调用 sync和await 总结 概述 最近在qq群里有一朋友,问起在winform中怎么通过开启线程的方式去处理耗时的操作,比如,查看某个目录下所有的文件,或 ...
- 【问题解决】线程间操作无效:从不是创建控件“textBox1”的线程访问它
背景 通过一个辅助线程计算出的一个值赋给textBox1.text: 解决办法 1.直接在窗体的构造函数中添加: System.Windows.Forms.Control.CheckForIllega ...
- C# 线程调用主线程中的控件
由于项目的需要,最近几天一直在做串口和数据库.由于C#使用的时间不长,所以在编写代码和调试的过程中总是遇到意想不到的问题,比如在使用串口接收数据的时候,在接收数据事件中想把接收的数据放入一个textb ...
- android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法
MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...
- Android子线程更新UI主线程方法之Handler
背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...
- 主线程中也不绝对安全的 UI 操作
从最初开始学习 iOS 的时候,我们就被告知 UI 操作一定要放在主线程进行.这是因为 UIKit 的方法不是线程安全的,保证线程安全需要极大的开销.那么问题来了,在主线程中进行 UI 操作一定是安全 ...
- 用Handler的post()方法来传递线程中的代码段到主线程中执行
自定义的线程中是不能更新UI的,但是如果遇到更新UI的事情,我们可以用handler的post()方法来将更新UI的方法体,直接传送到主线程中,这样就能直接更新UI了.Handler的post()方法 ...
随机推荐
- Codeforces Round #372 (Div. 2)
Codeforces Round #372 (Div. 2) C. Plus and Square Root 题意 一个游戏中,有一个数字\(x\),当前游戏等级为\(k\),有两种操作: '+'按钮 ...
- poj1062 最短路
题意:有n个物品,任务是得到1号物品,现在每个物品有它的主人,你可以用金钱购买物品,当然也可以用其他物品加上优惠的价格换取,但是有个要求,因为每个物品的主人有各自的等级,你所交易过的人中,等级差不能超 ...
- 【P1373】奶牛的卧室
看山神的题解写出来的,sro_dydxh_orz 原题:奶牛们有一个习惯,那就是根据自己的编号选择床号.如果一头奶牛编号是a,并且有0..k-1一共k张床,那么她就会选择a mod k号床作为她睡 ...
- 黑马程序员——JAVA基础之常用DOS命令和环境变量的配置
------- android培训.java培训.期待与您交流! ---------- 1.常用dos命令: dir 显示当前文件下目录 ...
- pdo的工作方式与查错
pdo某些方法如prepare()会返回PDOStatement对象; 然后需要通过返回的PDOStatement对象的方法操作 当查错通过$pdo->errInfo()方法可能查不出错误信息 ...
- GridView 控制分页页码间距
来源:http://auv2009.blog.163.com/blog/static/68858712200992793853431/ 技巧1:在分页区中改变当前页码的样式或高亮显示页码 一个简单的办 ...
- mysql join的方式结果集
一张图说明 left join, right join, inner join, full outer join
- html之span标签
对于文档中的行内元素最好使用span来组合它们,这样就可以通过样式来格式化它们. span没有任何的样式,当对它应用样式时,才会产生变化 id和class属性是span标签的好伴侣,这样做既可以增加适 ...
- ubuntu 安装 boost
1.tar -zxvf boost_1_43_0.tar.gz 2.cd boost_1_43_0, 执行: sudo ./bootstrap.sh sudo ./bjam install 检验安装 ...
- kettle常见问题解决
开源ETL工具kettle系列之常见问题 摘要:本文主要介绍使用kettle设计一些ETL任务时一些常见问题,这些问题大部分都不在官方FAQ上,你可以在kettle的论坛上找到一些问题的答案 1. J ...