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

   二:思路
  
因此,往往是新建一个线程,让他执行耗时的操作,主线程管理用户界面,不会出现UI假死的情况,但是通过线程获取到的数据如何更新回主进程的UI上呢?这是另外一个问题

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

 

TestClass.cs

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace WindowsFormsApplication1
{
public class TestClass
{
//声明一个delegate(委托)类型:TestDelegate,该类型可以搭载返回值为空,参数只有一个(long型)的方法。
public delegate void TestDelegate(long i); //声明一个TestDelegate类型的对象。该对象代表了返回值为空,参数只有一个(long型)的方法。它可以搭载N个方法。
public TestDelegate mainThread; /// 测试方法
/// <summary>
/// </summary>
public void TestFunction()
{
long i = ;
while (true)
{
i++;
mainThread(i); //调用委托对象
Thread.Sleep(); //线程等待1000毫秒
}
}
}
}

Program.cs

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
//创建TestClass类的对象
TestClass testClass = new TestClass(); //在testclass对象的mainThread(委托)对象上搭载两个方法,在线程中调用mainThread对象时相当于调用了这两个方法。
testClass.mainThread = new TestClass.TestDelegate(RefreshLabMessage1);
testClass.mainThread += new TestClass.TestDelegate(RefreshLabMessage2); //创建一个无参数的线程,这个线程执行TestClass类中的TestFunction方法。
Thread testClassThread = new Thread(new ThreadStart(testClass.TestFunction));
//启动线程,启动之后线程才开始执行
testClassThread.Start();
} /// <summary>
/// 在界面上更新线程执行次数
/// </summary>
/// <param name="i"></param>
private void RefreshLabMessage1(long i)
{
//判断该方法是否被主线程调用,也就是创建labMessage1控件的线程,当控件的InvokeRequired属性为ture时,说明是被主线程以外的线程调用。如果不加判断,会造成异常
if (this.labMessage1.InvokeRequired)
{
//再次创建一个TestClass类的对象
TestClass testclass = new TestClass();
//为新对象的mainThread对象搭载方法
testclass.mainThread = new TestClass.TestDelegate(RefreshLabMessage1);
//this指窗体,在这调用窗体的Invoke方法,也就是用窗体的创建线程来执行mainThread对象委托的方法,再加上需要的参数(i)
this.Invoke(testclass.mainThread, new object[] { i });
}
else
{
labMessage1.Text = i.ToString();
}
} /// <summary>
/// 在界面上更新线程执行次数
/// </summary>
/// <param name="i"></param>
private void RefreshLabMessage2(long i)
{
//同上
if (this.labMessage2.InvokeRequired)
{
//再次创建一个TestClass类的对象
TestClass testclass = new TestClass();
//为新对象的mainThread对象搭载方法
testclass.mainThread = new TestClass.TestDelegate(RefreshLabMessage2);
//this指窗体,在这调用窗体的Invoke方法,也就是用窗体的创建线程来执行mainThread对象委托的方法,再加上需要的参数(i)
this.Invoke(testclass.mainThread, new object[] { i });
}
else
{
labMessage2.Text = i.ToString();
}
}
}
}

执行效果

 

C#新开一个线程取到数据,如何更新到主线程UI上面的更多相关文章

  1. java的服务是每收到一个请求就新开一个线程来处理吗?tomcat呢?

    首先,服务器的实现不止有这两种方式. 先谈谈题主说的这两种服务器模型: 1.收到一个请求就处理,这个时候就不能处理新的请求,这种为阻塞 这个是单线程模型,无法并发,一个请求没处理完服务器就会阻塞,不会 ...

  2. BeginInvoke 方法真的是新开一个线程进行异步调用吗?

    转自原文BeginInvoke 方法真的是新开一个线程进行异步调用吗? BeginInvoke 方法真的是新开一个线程进行异步调用吗? 参考以下代码: public delegate void tre ...

  3. [转]MFC子线程更改图像数据后更新主窗口图像显示方法

    程序思路是由外部的输入输出控制卡发出采集图像信号,之后相机采集图像得到图像数据指针,接收图像数据指针创建成图像最后显示到MFC对话框应用程序的Picture Control控件上,同时,为了标定相机位 ...

  4. WinForm中新开一个线程操作 窗体上的控件(跨线程操作控件)

    最近在做一个winform的小软件(抢票的...).登录窗体要从远程web页面获取一些数据,为了不阻塞登录窗体的显示,开了一个线程去加载数据远程的数据,会报一个错误"线程间操作无效: 从不是 ...

  5. Python+Selenium练习篇之15-在浏览器中新开一个tab

    本文介绍如selenium方法打开一个新的tab,我们知道在浏览器里,我们按住 ctrl+ t 就可以新打开一个tab.所以我们学习如何利用webdriver中send_key 的方法去触发ctrl+ ...

  6. SQL存在一个表而不在另一个表中的数据, 更新字段为随机时间

    --更新字段为随机时间 86400秒=1天 UPDATE dl_robot ), ,GETDATE()) )   SQL存在一个表而不在另一个表中的数据   方法一 使用 not in ,容易理解,效 ...

  7. 开源一个爬取redmine数据的测试报告系统

    背景 软件测试的最后有一道比较繁琐的工作,就是编写测试报告.手写测试报告在数据统计和分析上面要耗费比较大的事件和精力.之前工作室使用mantis管理bug缺陷.公司有内部有个系统,可以直接从manti ...

  8. shell脚本,怎么实现每次新开一个shell都输出一个提示语?

    [root@localhost wyb]# cat test.sh echo -e "\033[32mhello,This is wangyuebo's shell\033[0m" ...

  9. 怎么新开一个组件并且配置路由?vue-cli

    首先要明白: 路由就是url路径,如果一个组件被引入到了另外一个组件,这个页面就包含这个组件了,所以这个被包含的组件不要去路由哪里配置了 第一步: 先写上想要添加的组件 2.组件的内容 3.路由的配置 ...

随机推荐

  1. css三角形

    <html><head> <meta charset="UTF-8"></head><style> div{float: ...

  2. jsp中利用response.senddirect(str)重定向,传递参数新思路

    用Servlet进行请求重定向,参数传递好办,直接用request.setAttribute(str1,str2); 但是如果不用Servlet 而是直接用jsp进行转发呢? 我们首先要知道   请求 ...

  3. csc一些命令简记

    C#在命令行进行编译的一些命令: csc使用详解 @echo off cd / cd C:\Program Files (x86)\MSBuild\12.0\Bin set /p var= 请输入文件 ...

  4. webAPI 自动生成帮助文档

    之前在项目中有用到webapi对外提供接口,发现在项目中有根据webapi的方法和注释自动生成帮助文档,还可以测试webapi方法,功能很是强大,现拿出来与大家分享一下. 先看一下生成的webapi文 ...

  5. python 列表生成器

    python 列表生成器 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 一个循环 在C语言等其他语言中,for循环一般是这样的 ...

  6. [ACM_其他] 总和不小于S的连续子序列的长度的最小值——尺缩法

    Description: 给定长度为n的整数数列,A[0],A[1],A[2]….A[n-1]以及整数S,求出总和不小于S的连续子序列的长度的最小值.如果解不存在,则输出0. Input: 输入数据有 ...

  7. SignalR 简单示例

    一.什么是 SignalR ASP.NET SignalR is a library for ASP.NET developers that simplifies the process of add ...

  8. LINQ-to-SQL那点事~LINQ-to-SQL中的并发冲突与应对

    回到目录 在上一篇文章中提到了并发冲突,还说详细的说明在这讲来说,呵呵,那现在就说一下吧! 并发冲突产生的原因 事实上,linq to sql中的并发冲突是指记录在进行update操作时,客户端A1取 ...

  9. atitit.常用编程语言的性能比较 c c++ java

    atitit.常用编程语言的性能比较 c c++ java 选择一个什么样的程序问题进行这样的测试呢?这是一个很关键的问题,也最容易影响测试的公平性.另外的,对于每种语言,各自的优势都是不同的 #-- ...

  10. bzoj 1637: [Usaco2007 Mar]Balanced Lineup

    1637: [Usaco2007 Mar]Balanced Lineup Time Limit: 5 Sec  Memory Limit: 64 MB Description Farmer John ...