zoukankan      html  css  js  c++  java
  • 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.cs

     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 }

    执行效果 

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

  • 相关阅读:
    CentOS安装部署Nodejs
    CentOS安装部署Git
    CentOS安装部署Mysql 5.7
    CentOS 7 安装Java环境(脚本一键式安装)
    Java技术 | 细谈Java中UUID的简单了解与使用
    Navicat Premium 版本 12.1 激活成永久
    Java技术 | 细谈 Java 8 中的 Base64
    安装部署Elastic Search
    从零开始搭建linux下laravel 5.5所需环境(二)
    从零开始搭建linux下laravel 5.5所需环境(一)
  • 原文地址:https://www.cnblogs.com/menglin2010/p/5391285.html
Copyright © 2011-2022 走看看