C#新开一个线程取到数据,如何更新到主线程UI上面


   一:问题
  
以前有被面试官问过,在WinForm中,要去网络上获取数据,因为网络环境等缘由,不能很快的完成,所以会发生进程阻塞,形成主进程假死的现象,须要怎么解决?
面试

   二:思路
  
所以,每每是新建一个线程,让他执行耗时的操做,主线程管理用户界面,不会出现UI假死的状况,可是经过线程获取到的数据如何更新回主进程的UI上呢?这是另一个问题

   三:以下例子
  
咱们发现若是直接在线程里更新UI会报错,报“从不是建立控件lable1的线程访问它”,为何会报这个错呢?这个问题就是跨线程访问控件问题,窗体上的控件只容许建立它们的线程访问,也就是主线程(UI线程),若是非主线程访问则会发生异常咱们看到会报错,且这个错误是“从不是建立控件lable1的线程访问它”网络

 
这里写图片描述

TestClass.cs
测试

 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading;
 6 using System.Threading.Tasks;
 7 
 8 namespace WindowsFormsApplication1
 9 {
10     public class TestClass
11     {
12         //声明一个delegate(委托)类型:TestDelegate,该类型能够搭载返回值为空,参数只有一个(long型)的方法。 
13         public delegate void TestDelegate(long i);
14 
15         //声明一个TestDelegate类型的对象。该对象表明了返回值为空,参数只有一个(long型)的方法。它能够搭载N个方法。 
16         public TestDelegate mainThread;
17 
18         /// 测试方法 
19         /// <summary>          
20         /// </summary> 
21         public void TestFunction()
22         {
23             long i = 0;
24             while (true)
25             {
26                 i++;
27                 mainThread(i); //调用委托对象 
28                 Thread.Sleep(1000);  //线程等待1000毫秒 
29             }
30         }
31     }
32 }

 

Program.csui

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Data;
 5 using System.Drawing;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Threading;
 9 using System.Threading.Tasks;
10 using System.Windows.Forms;
11 
12 namespace WindowsFormsApplication1
13 {
14     public partial class Form1 : Form
15     {
16         public Form1()
17         {
18             InitializeComponent();
19         }
20 
21         private void button1_Click(object sender, EventArgs e)
22         {
23             //建立TestClass类的对象 
24             TestClass testClass = new TestClass();
25 
26             //在testclass对象的mainThread(委托)对象上搭载两个方法,在线程中调用mainThread对象时至关于调用了这两个方法。 
27             testClass.mainThread = new TestClass.TestDelegate(RefreshLabMessage1);
28             testClass.mainThread += new TestClass.TestDelegate(RefreshLabMessage2);
29 
30             //建立一个无参数的线程,这个线程执行TestClass类中的TestFunction方法。 
31             Thread testClassThread = new Thread(new ThreadStart(testClass.TestFunction));
32             //启动线程,启动以后线程才开始执行 
33             testClassThread.Start();
34         }
35 
36         /// <summary> 
37         /// 在界面上更新线程执行次数 
38         /// </summary> 
39         /// <param name="i"></param> 
40         private void RefreshLabMessage1(long i)
41         {
42             //判断该方法是否被主线程调用,也就是建立labMessage1控件的线程,当控件的InvokeRequired属性为ture时,说明是被主线程之外的线程调用。若是不加判断,会形成异常 
43             if (this.labMessage1.InvokeRequired)
44             {
45                 //再次建立一个TestClass类的对象 
46                 TestClass testclass = new TestClass();
47                 //为新对象的mainThread对象搭载方法 
48                 testclass.mainThread = new TestClass.TestDelegate(RefreshLabMessage1);
49                 //this指窗体,在这调用窗体的Invoke方法,也就是用窗体的建立线程来执行mainThread对象委托的方法,再加上须要的参数(i) 
50                 this.Invoke(testclass.mainThread, new object[] { i });
51             }
52             else
53             {
54                 labMessage1.Text = i.ToString();
55             }
56         }
57 
58 
59         /// <summary> 
60         /// 在界面上更新线程执行次数 
61         /// </summary> 
62         /// <param name="i"></param> 
63         private void RefreshLabMessage2(long i)
64         {
65             //同上 
66             if (this.labMessage2.InvokeRequired)
67             {
68                 //再次建立一个TestClass类的对象 
69                 TestClass testclass = new TestClass();
70                 //为新对象的mainThread对象搭载方法 
71                 testclass.mainThread = new TestClass.TestDelegate(RefreshLabMessage2);
72                 //this指窗体,在这调用窗体的Invoke方法,也就是用窗体的建立线程来执行mainThread对象委托的方法,再加上须要的参数(i) 
73                 this.Invoke(testclass.mainThread, new object[] { i });
74             }
75             else
76             {
77                 labMessage2.Text = i.ToString();
78             }
79         }
80     }
81 }

执行效果 this

这里写图片描述 
这里写图片描述

相关文章
相关标签/搜索