C#后台线程和UI的交互
http://www.cnblogs.com/Wizardh/articles/963097.html
在C#中,从Main()方法开始一个默认的线程,一般称之为主线程,如果在这个进行一些非常耗CPU的计算,那么UI界面就会被挂起而处于假死状态,也就是说无法和用户进行交互了,特别是要用类似进度条来实时显示一些提示信息的时候,这种情况就显得很糟糕。如果多开一些线程来完成一些耗时的计算,那么工作线程也是无法如此更新UI界面中的元素的,比如直接显示一个提示信息:label1.Text=outstring,原因很简单UI属于默认的主线程,而线程间是不能这样直接访问彼此的成员的。
如果要解决以上的两个问题,那么可以借助C#中的Delegate和控件类中的Invoke()方法来搞定。
这里给出的例子比较简单,主要思路是:在Main()中启动其它的线程作为后台进程,其中一个线程是实时显示当前的时间,一个线程是显示一些随机数,这样一来三个线程同时运行,彼此通过代理来联系。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;
namespace MutliThreadedWinFormsApp
{
public class Form1 : System.Windows.Forms.Form
{
private Thread currentTimeThread = null;
private Thread randomNumbersThread = null;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox currentTime;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox randomNumbers;
private System.Windows.Forms.GroupBox threadManager;
private System.Windows.Forms.Button pause;
private System.Windows.Forms.Button stop;
private System.Windows.Forms.Button start;
private System.Windows.Forms.RadioButton manageTime;
private System.Windows.Forms.RadioButton manageNumbers;
private System.Windows.Forms.RadioButton manageBoth;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
//创建新的工作线程
currentTimeThread = new Thread(new ThreadStart(CountTime));
currentTimeThread.IsBackground = true;
randomNumbersThread = new Thread(new ThreadStart(GenerateRandomNumbers));
randomNumbersThread.IsBackground = true;
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
UI设计#region UI设计
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.currentTime = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.randomNumbers = new System.Windows.Forms.TextBox();
this.threadManager = new System.Windows.Forms.GroupBox();
this.manageBoth = new System.Windows.Forms.RadioButton();
this.manageNumbers = new System.Windows.Forms.RadioButton();
this.manageTime = new System.Windows.Forms.RadioButton();
this.pause = new System.Windows.Forms.Button();
this.stop = new System.Windows.Forms.Button();
this.start = new System.Windows.Forms.Button();
this.threadManager.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(8, 24);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(79, 13);
this.label1.TabIndex = 0;
this.label1.Text = "现在的时间:";
//
// currentTime
//
this.currentTime.Location = new System.Drawing.Point(88, 23);
this.currentTime.Name = "currentTime";
this.currentTime.ReadOnly = true;
this.currentTime.Size = new System.Drawing.Size(157, 20);
this.currentTime.TabIndex = 1;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(14, 56);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(43, 13);
this.label2.TabIndex = 2;
this.label2.Text = "随机数";
//
// randomNumbers
//
this.randomNumbers.Location = new System.Drawing.Point(16, 72);
this.randomNumbers.Name = "randomNumbers";
this.randomNumbers.ReadOnly = true;
this.randomNumbers.Size = new System.Drawing.Size(229, 20);
this.randomNumbers.TabIndex = 3;
//
// threadManager
//
this.threadManager.Controls.Add(this.manageBoth);
this.threadManager.Controls.Add(this.manageNumbers);
this.threadManager.Controls.Add(this.manageTime);
this.threadManager.Controls.Add(this.pause);
this.threadManager.Controls.Add(this.stop);
this.threadManager.Controls.Add(this.start);
this.threadManager.Location = new System.Drawing.Point(16, 104);
this.threadManager.Name = "threadManager";
this.threadManager.Size = new System.Drawing.Size(229, 154);
this.threadManager.TabIndex = 7;
this.threadManager.TabStop = false;
this.threadManager.Text = "工作线程控制";
//
// manageBoth
//
this.manageBoth.Location = new System.Drawing.Point(34, 74);
this.manageBoth.Name = "manageBoth";
this.manageBoth.Size = new System.Drawing.Size(104, 16);
this.manageBoth.TabIndex = 12;
this.manageBoth.Text = "同时运行";
this.manageBoth.CheckedChanged += new System.EventHandler(this.manageBoth_CheckedChanged);
//
// manageNumbers
//
this.manageNumbers.Location = new System.Drawing.Point(34, 50);
this.manageNumbers.Name = "manageNumbers";
this.manageNumbers.Size = new System.Drawing.Size(104, 16);
this.manageNumbers.TabIndex = 11;
this.manageNumbers.Text = "更新随机数线程";
this.manageNumbers.CheckedChanged += new System.EventHandler(this.manageNumbers_CheckedChanged);
//
// manageTime
//
this.manageTime.Location = new System.Drawing.Point(34, 26);
this.manageTime.Name = "manageTime";
this.manageTime.Size = new System.Drawing.Size(104, 16);
this.manageTime.TabIndex = 10;
this.manageTime.Text = "更新时间线程";
this.manageTime.CheckedChanged += new System.EventHandler(this.manageTime_CheckedChanged);
//
// pause
//
this.pause.Location = new System.Drawing.Point(84, 115);
this.pause.Name = "pause";
this.pause.Size = new System.Drawing.Size(54, 23);
this.pause.TabIndex = 9;
this.pause.Text = "暂停";
this.pause.Click += new System.EventHandler(this.pause_Click);
//
// stop
//
this.stop.Location = new System.Drawing.Point(158, 115);
this.stop.Name = "stop";
this.stop.Size = new System.Drawing.Size(51, 23);
this.stop.TabIndex = 8;
this.stop.Text = "停止";
this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
this.start.Location = new System.Drawing.Point(6, 115);
this.start.Name = "start";
this.start.Size = new System.Drawing.Size(50, 23);
this.start.TabIndex = 7;
this.start.Text = "开始";
this.start.Click += new System.EventHandler(this.start_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(253, 271);
this.Controls.Add(this.threadManager);
this.Controls.Add(this.randomNumbers);
this.Controls.Add(this.label2);
this.Controls.Add(this.currentTime);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "工作线程和UI的交互";
this.Closing += new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
this.threadManager.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void start_Click(object sender, System.EventArgs e)
{
bool bTime = false, bRandomNumbers = false;
if( manageTime.Checked || manageBoth.Checked )
bTime = true;
if( manageNumbers.Checked || manageBoth.Checked )
bRandomNumbers = true;
if( bTime )
currentTimeThread.Start();
if( bRandomNumbers )
randomNumbersThread.Start();
start.Enabled = false;
stop.Enabled = true;
pause.Enabled = true;
}
private void stop_Click(object sender, System.EventArgs e)
{
bool bTime = false, bRandomNumbers = false;
if( manageTime.Checked == true || manageBoth.Checked == true )
bTime = true;
if( manageNumbers.Checked == true || manageBoth.Checked == true )
bRandomNumbers = true;
if( bTime )
{
currentTimeThread.Abort();
currentTimeThread.Join();
currentTimeThread = new Thread(new ThreadStart(CountTime));
currentTimeThread.IsBackground = true;
}
if( bRandomNumbers )
{
randomNumbersThread.Abort();
randomNumbersThread.Join();
randomNumbersThread = new Thread(new ThreadStart(GenerateRandomNumbers));
randomNumbersThread.IsBackground = true;
}
start.Enabled = true;
stop.Enabled = false;
pause.Enabled = false;
}
private void pause_Click(object sender, System.EventArgs e)
{
bool bTime = false, bRandomNumbers = false;
if( manageTime.Checked == true || manageBoth.Checked == true )
bTime = true;
if( manageNumbers.Checked == true || manageBoth.Checked == true )
bRandomNumbers = true;
if( bTime )
{
if( 0 != (currentTimeThread.ThreadState & ( ThreadState.Suspended | ThreadState.SuspendRequested ) ) )
currentTimeThread.Resume();
else
currentTimeThread.Suspend();
}
if( bRandomNumbers )
{
if( 0 != (randomNumbersThread.ThreadState & ( ThreadState.Suspended | ThreadState.SuspendRequested ) ) )
randomNumbersThread.Resume();
else
randomNumbersThread.Suspend();
}
}
private void manageTime_CheckedChanged(object sender, System.EventArgs e)
{
}
private void manageNumbers_CheckedChanged(object sender, System.EventArgs e)
{
}
private void manageBoth_CheckedChanged(object sender, System.EventArgs e)
{
}
/**//// <summary>
/// 注意其Invoke的使用,其有两种使用形式
/// public void Invoke(System.Delegate delegate);
/// public void Invoke(System.Delegate delegate, object [] args);
/// </summary>
public void CountTime()
{
while(true)
{
Invoke(new UpdateTimeDelegate(updateCurrentTime));
Thread.Sleep(1000);
}
}
public void GenerateRandomNumbers()
{
int [] randomNumbers = new int[10];
Random r = new Random();
while(true)
{
for(int i = 0; i < randomNumbers.Length; i++)
randomNumbers[i] = r.Next(1, 100);
Invoke(new UpdateRandomNumbers(updateRandomNumbers), new object[] { randomNumbers });
Thread.Sleep(500);
}
}
/**//// <summary>
/// 负责更新UI界面中时间显示的函数
/// </summary>
private void updateCurrentTime()
{
currentTime.Text = DateTime.Now.ToLongTimeString();
}
/**//// <summary>
/// 负责更新UI界面中随机数显示的函数
/// </summary>
/// <param name="numbers"></param>
private void updateRandomNumbers(int [] numbers)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach(int i in numbers)
sb.Append(i.ToString()).Append(", ");
randomNumbers.Text = sb.ToString();
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if( (randomNumbersThread.ThreadState & ThreadState.Running) == ThreadState.Running )
randomNumbersThread.Abort();
randomNumbersThread = null;
if( (currentTimeThread.ThreadState & ThreadState.Running) == ThreadState.Running )
currentTimeThread.Abort();
currentTimeThread = null;
}
}
public delegate void UpdateTimeDelegate();
public delegate void UpdateRandomNumbers(int [] numbers);
}
其实在C# 2.0 中所有的Control类都有Invoke()方法,如果负责更新UI元素的函数不是定义在Main()中,那么必须首先检测Control类中的InvokeRequired属性。举个例子吧,注意setProgressBarValue()函数中调用自己的方式.
//在工作线程中更新主窗口进度条
public void setProgressBarValue(ProgressBar progressBar1,int value)
{
if (progressBar1.InvokeRequired)
{
object[] parameters = new object[] { value };
progressBar1.Invoke(new setProgressBarValueDelegate(setProgressBarValue), parameters);
}
else
progressBar1.Value = value;
}
这里的一些代码参考了http://www.codeproject.com 的例子.
转载于:https://www.cnblogs.com/l1b2q31/articles/2195708.html
C#后台线程和UI的交互相关推荐
- AndroidUI——后台线程更新UI的几种方式
开发Android程序时经常会用到后台线程请求服务器数据,当请求完数据后更新UI时,经常遇到回调函数中和UI相关的语句无法执行,甚至有时候会抛异常. 下面的例子我会讲到三种方法更新UI,例子非常简单, ...
- winform 后台线程更新UI
//后台线程更新TextBoxprivate void SetTextBox(TextBox txt, string value){Action act = () =>{txt.Text = v ...
- Android中后台线程如何与UI线程交互
我想关于这个话题已经有很多前辈讨论过了.今天算是一次学习总结吧. 在android的设计思想中,为了确保用户顺滑的操作体验.一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务.因此我们必须 ...
- wxpython后台如何更新界面信息_wxpython后台线程更新界面控件方法
在大多数的GUI应用程序中,在应用程序的后台中长期执行一个处理过程而不干涉用户与应用程序的其它部分的交互是有好处的.允许后台处理的机制通常是产生一个线程并在该线程中长期执行一个处理过程.对于wxPyt ...
- wxpython后台线程更新界面控件方法
http://blog.sina.com.cn/s/blog_56146dc501009ea9.html http://www.th7.cn/Program/Python/201303/128088. ...
- 当进度对话框和后台线程处于活动状态时,如何处理屏幕方向变化?
我的程序在后台线程中执行一些网络活动. 在开始之前,它会弹出一个进度对话框. 该对话框在处理程序上关闭. 这一切都可以正常工作,除非对话框打开(并且背景线程正在运行)时屏幕方向发生变化. 此时,应用程 ...
- .NET一个线程更新另一个线程的UI(两种实现方法及若干简化)
本片博文接上一篇:.NET多线程执行函数,给出实现一个线程更新另一个线程UI的两种方法. Winform中的控件是绑定到特定的线程的(一般是主线程),这意味着从另一个线程更新主线程的控件不能直接调用该 ...
- Android非UI线程更新UI的几种方法
2019独角兽企业重金招聘Python工程师标准>>> Android用于实现非UI线程与UI线程的交互方法如下: 1.Handler 2.Activity.runOnUIThrea ...
- android 组件 线程,Android UI线程和非UI线程
UI线程及Android的单线程模型原则 当应用启动,系统会创建一个主线程(main thread). 这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的 ...
最新文章
- Linux配置免密登录
- keil 函数 默认 外部 内部 博客_5.9 C++内部函数与外部函数
- Kubernetes APIServer机制概述
- HTML5 input 类型
- 重磅福利 | 全网唯一,多年踩坑经验,探索测试策略新奇方法之案例剖析(一)...
- 数学建模-14.主成分分析PCA
- js获取页面宽度给JS div设宽度
- 通过--amend和rebase修改git commit提交的注释信息
- W3C school
- mac os监听扬声器、麦克风的音量、静音
- DBFS解二阶魔方——一次c++学习之旅
- Go标准库syscall调用dll
- statusBar控件
- 构造方法的定义、重载、调用、使用 (1)定义商品类Goods,
- 从来只留一场梦 一场春梦成白头 上软疑似解体 忆仙剑而作
- 无线网卡+kali实现wifi暴力破解(密码爆破方式)
- (语言学知识,勿点)越南语第一章
- SAP OData 编程指南
- Dropbox和其他备份产品概述
- 解决VirtualBox只能安装32位系统的问题
热门文章
- 本科计算机科学与技术专业物理,中国工程物理研究院职工工学院计算机科学与技术(本科)专业介绍...
- android adapter排序,Android BindingAdapter执行顺序?
- python能做大型网站么_前几天有人讨论Python做的大型网站
- 072_Math对象
- android教程登陆,【教程】Android 记住密码和自动登录界面的实现
- 如何根据分页的当前页数查询数据_数据量很大的情况下,如何分页查询优化方案?...
- 如何为linux 桌面文件内存,linux - 桌面Linux发行版中.desktop文件的功能是什么? - 堆栈内存溢出...
- webstorm配置环境变量_webstorm中配置nodejs环境及npm步骤详细解说
- python社区发现_这个 Python 项目厉害了!多个实战案例教你分析时空数据处理
- java 微网站_java架构之路-(微服务专题)初步认识微服务与nacos初步搭建