关于Winform中控件的跨线程访问

闲着没事想起来用winform做一个随机的抽号程序,咋看来这么个东西其实并不难,不过对于一个菜鸟来说其实并不简单!尤其是对于多线程不是特别熟悉的新手来说。

首先,界面比较简单winform,(图片上传好麻烦~~!)

既然是随机抽取号码,就得有随机数(其实关键不在这里,图省事就random了)

可是在用到多线程的时候问题就出现了:

无法跨线程访问label控件,无法修改label的text。

网上找了很多资料,感觉例子搞得难以理解,遂自己撸起。。。。

1.有人这么写:

// Control.CheckForIllegalCrossThreadCalls = false;
//Label.CheckForIllegalCrossThreadCalls = false;

个人感觉这么干绝逼不合适,遂放弃!(原因有很多)

2.参考资料-用委托:

试着用委托的方式去解决,可无奈不知为何,使用了委托之后随机数字没有了滚动,最后直接界面卡死,(似乎没什么效果╮(╯-╰)╭)

3.使用invok调事件传方法。如代码所示

11
12 namespace 抽奖程序
13 {
14     public partial class Form1 : Form
15     {
16
17
18         public Form1()
19         {
20             InitializeComponent();
21         }
22         bool stateFlag = false;//暂停标识
23         Random r = new Random();//随机数对象
24
25         private void startNum_Click(object sender, EventArgs e)
26         {
27             if (!stateFlag)
28             {
29                 startNum.Text = "暂停";//改变按钮文本
30                 stateFlag = true;
31                 Thread th = new Thread(StartRandom);//开启线程
32                 th.IsBackground = true;//标识后台线程
33                 th.Start();
34
35             }
36             else
37             {
38                 startNum.Text = "开始";
39                 stateFlag = false;
40             }
41
42
43         }
44         /// <summary>
45         /// 生成随机数方法,使用控件的invoke方法刷新label,实现数字滚动
46         /// </summary>
47         private void StartRandom()
48         {
49             int r1;
50             int r2;
51             int r3;
52             while (stateFlag)
53             {
54                 r1 = r.Next(0, 10);//生成label1的随机数
55                 r2 = r.Next(0, 10);//生成label2的随机数
56                 r3 = r.Next(0, 10);//生成label3的随机数
57                 if (label1.InvokeRequired)
58                 {
59                     this.label1.Invoke(new Action<Label, string>(setvalue), this.label1, r1.ToString());
60                 }
61                 if (label2.InvokeRequired)
62                 {
63                     this.label2.Invoke(new Action<Label, string>(setvalue), this.label2, r2.ToString());
64                 }
65
66                 if (label3.InvokeRequired)
67                 {
68                     this.label3.Invoke(new Action<Label, string>(setvalue), this.label3, r3.ToString());
69                 }
70             }
71         }
72
73         /// <summary>
74         /// 改变label数字
75         /// </summary>
76         /// <param name="lab"></param>
77         /// <param name="lbvalue"></param>
78         private void setvalue(Label lab, string lbvalue)
79         {
80             lab.Text = lbvalue;
81         }
82
83
84         private void Form1_Load(object sender, EventArgs e)
85         {
86             //Control.CheckForIllegalCrossThreadCalls = false;关闭跨线程检测。。。
87             //Label.CheckForIllegalCrossThreadCalls = false;
88             startNum.Text = "开始";
89         }
90     }
91 }

总结:

其实2、3原理基本一致,后来找问题时候发现其实是用委托的时候代码放错了位置(滚去面壁!)

控件只能由创建它的线程来访问。其他线程想访问必须调用该控件的Invoke方法。Invoke有两个参数,一个是委托方法,一个是参数值。

是用事件还是用委托(随便的啦~)。

菜鸟第一篇笔记,写得比较烂,勿转勿喷,仅此献给新手

时间: 2024-08-24 09:12:47

关于Winform中控件的跨线程访问的相关文章

C#中WinForm控件的跨线程更新Invoke

目的: 用WinForm(C#)搭建一个用户界面,一个进度条和一个按钮,按钮启动进度条,进度完成时停止更新 示例: 实现: 在按钮事件中设置循环,更新进度条         private void btnProgress_Click(object sender, EventArgs e)         {             for (int ii = 0; ii < 100; ii++)             {                 progressBar1.Value 

WinForm跨线程访问控件异常

WinForm跨线程访问控件异常 最近做了个WinForm的小项目,遇到个简单的问题记录下.需求:点击"下载",显示正在下载,下载完后更新状态为"ready"(要求用多线程,避免前台卡死). 做法 新建一个线程,在新线程中下在更新控件状态,报异常跨线程程访问控件(当然可以通过关闭跨线程访问控件检验解决,不鼓励这么做).应该C#5.0版本添加的任务Task异步,这里用异步解决. Code 新建WinForm 项目,Form1添加控件如图 后台代码 private vo

Winform之跨线程访问控件(在进度条上显示字体)

此文章对于遇到必须使用线程但是没有办法在线程内操作控件的问题的处理  有很好的解决方案(个人认为的.有更好的方案欢迎交流.) 在做跨线程访问之前我们先了解下我们所做的需要达到的效果: 这个是批量的将xml文件导入sqlite数据库   每个xml有将近3000的节点  每个节点有5个属性,如果我们不用线程那么在数据导入的过程中   程序很可能卡死   而且基本上动不了,用户的体验性就很差. 所以我们对向数据库添加数据的地方使用了线程: Thread thread = new Thread(new

C#中使用多线程访问Winform中控件的若干问题

我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍. 首先来看传统方法: public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Thread thread = new Thread(Thread

线程间操作无效: 从不是创建控件“控件id”的线程访问它。(.net跨线程执行方法)

找了好久资料,终于解决了,特此记录下来. 1 delegate void DelListHandler(string number); /// <summary> /// 按标识删除listview内容 /// </summary> /// <param name="number">标识</param> private void DelListViewLog(string number) { for (int i = 0; i <

C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它

C# 委托 / 跨线程访问UI /  线程间操作无效: 从不是创建控件"Form1"的线程访问它 网上的代码都比较复杂,还是这个简单 见代码, 简易解决办法: 主窗体代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; usi

c#使用MethodInvoker解决跨线程访问控件

功能函数测试集锦(77)  C#专区(114)  版权声明:本文为博主原创文章,未经博主允许不得转载. .net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生,有一种方法是禁止编译器对跨线程访问作检查,Control.CheckForIllegalCrossThreadCalls = false;可以实现访问,但是出不出错不敢保证C#跨线程访问控件运行时错误. 使用MethodInvoker即可解决: 原代码: private void btnOK_Click(object sender

2 跨线程访问控件InvokeHelper类

这里是一张动画,演示在多线程(无限循环+Thread.Sleep)情况下主界面操作不受影响. 多线程是一种提高程序运行效率和性能的常用技术.随着我们学习工作的深入,在编程中或多或少会涉及到需要多线程的情况.多数时候,我们的操作模式是后台线程中处理数据,计算结果,然后在前台界面(GUI)中更新显示. 在.NET Framework中,为了保证线程安全,避免出现访问竞争等问题,是不允许跨线程访问窗体控件的.如果强行访问,则会引发InvalidOperationException无效操作异常,如下图:

跨线程访问控件的方法

主窗体创建的控件相当于主线程管理,在分线程使用的时候会产生跨线程访问的问题,这时需要如下判断写法,即可解决 if (lblNum2.InvokeRequired) { lblNum2.Invoke(new Action<string>(s => { this.lblNum2.Text = s; }), Thread.CurrentThread.ManagedThreadId.ToString()); } else { this.lblNum2.Text = Guid.NewGuid().