.NET WinForm编程Q&A系列(一)——多线程操作
来源:互联网 发布:惠州asm先进科技 知乎 编辑:程序博客网 时间:2024/05/22 00:23
前言
当有大量.NET程序员进入这个领域后,利用"即见即所得"的机制我们可以快速的开发出了很多应用程序,但是随着深入这个领域,我们会发现,有UI的设计往往不能开发出比较理想的系统原型,甚至有1~3年经验的.NET程序员仍然不能理解诸多概念,如C#的高级语法(属性、索引器、委托、事件)、常用的命名空间的用法、Winform的使用、线程的知识,包括我本人也是如此。所以《.NET WinForm编程Q&A系列》就是基于本人的理解能力进行整理。整个系列都会包括如下内容:
【背景】重点提出WinForm编程中的问题以及相关晦涩的概念;
【概念】教科书或者百度百科关于这些问题以及概念的介绍,我估计大多数程序员不愿意接受这种方式;
【需求】对应这些问题以及概念,本人提出了一个系统实例,并希望借助这个实例可以对背景提出的若干问题进行求解,也让大家对概念进行一个梳理;
【实战】详细介绍实例的实现过程,当然针对实例,会有很多的解决方案,本文所提出的实战过程仅仅是其中一种。
【备注】欢迎大家提出宝贵意见。
背景
如何理解并应用多线程操作?
概念
1、多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的;
2、使用线程可以把占据时间长的程序中的任务放到后台去处理;
3、在本质上和结构来说,.NET是一个多线程的环境。有两种主要的多线程方法是.NET所提倡的:使用ThreadStart来开始你自己的进程,直接的(使用ThreadPool.QueueUserWorkItem)或者间接的(比如Stream.BeginRead,或者调用BeginInvoke)使用ThreadPool类。一般来说,你可以"手动"为长时间运行的任务创建一个新的线程,另外对于短时间运行的任务尤其是经常需要开始的那些,进程池是一个非常好的选择。进程池可以同时运行多个任务,还可以使用框架类。对于资源紧缺需要进行同步的情况来说,它可以限制某一时刻只允许一个线程访问资源。这种情况可以视为给线程实现了锁机制。线程的基类是System.Threading。所有线程通过CLI来进行管理。
需求
控件内容的定时变更,每隔1秒,文本控件将显示一个随机数(0,100),进度条进行显示。
如下图所示。
实战
1、根据需求中提到的系统要求,初级的程序员会快速的写出方案,如下所示:
private void button1_Click(object sender, EventArgs e) { while (true) { Random rd = new Random(); int num = rd.Next(0, 100); this.textBox1.Text = num.ToString(); Thread.Sleep(1000); } }
2、一旦运行后,发现界面动不了,于是又考虑用计数器实现,如下:
private void button1_Click(object sender, EventArgs e) { this.timer1.Enabled = true; } private void timer1_Tick(object sender, EventArgs e) { Random rd = new Random(); int num = rd.Next(0, 100); this.textBox1.Text = num.ToString(); this.progressBar1.Value = num; Thread.Sleep(1000); }3、此时F5后,发现系统正常运作了,这就是其中的一种解决方案,但是本文主要是要介绍多线程,所以我们考虑其他的步骤。
4、要使用多线程控制UI控件,必须用委托实现。调用控件的Invoke方法(Invoke方法的参数是一个委托类型的参数)。
具体步骤如下所示:
1.声明委托。
/// <summary> /// 1.声明委托 /// </summary> /// <param name="num"></param> delegate void RefreshData(int num); delegate void AutoRefresh();2.声明委托处理函数(判断是主线程控制UI控件,还是Invoke(多线程)控制UI控件)。
/// <summary> /// 2.声明委托处理函数refreshTextBox /// </summary> /// <param name="num"></param> public void refreshTextBox(int num) { if (this.textBox1.InvokeRequired) { RefreshData rd = new RefreshData(refreshTextBox); if (this.textBox1.IsHandleCreated) { this.textBox1.Invoke(rd, num); } } else { this.textBox1.Text = num.ToString(); } } /// <summary> /// 2.声明委托处理函数Display /// </summary> /// <param name="num"></param> public void Display(int num) { if (this.progressBar1.InvokeRequired) { RefreshData rd = new RefreshData(Display); if (this.progressBar1.IsHandleCreated) { this.progressBar1.Invoke(rd, num); } } else { this.progressBar1.Value = num; } }3.声明一个线程实例,将线程函数的委托传入ThreadStart()。
//3.声明一个线程实例Thread refreshThread = new Thread(new ThreadStart(ar));4.开启该线程。
//4.开启该线程refreshThread.Start();5.定义该线程函数,欲控制UI控件,则调用第2步的委托处理函数,他将自己判断选择用Invoke。
6.定义Invoke需要调用的函数
/// <summary> /// 6.定义Invoke需要调用的函数 /// </summary> private void AddAuto() { while (true) { Random rd = new Random(); int num = rd.Next(0, 100); refreshTextBox(num); Display(num); } }
备注
代码全集如下:
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading;namespace MulControlOp{ public partial class Form1 : Form { /// <summary> /// 1.声明委托 /// </summary> /// <param name="num"></param> delegate void RefreshData(int num); delegate void AutoRefresh(); public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { AutoRefresh ar = new AutoRefresh(AddAuto); //3.声明一个线程实例 Thread refreshThread = new Thread(new ThreadStart(ar)); //4.开启该线程 refreshThread.Start(); } /// <summary> /// 6.定义Invoke需要调用的函数 /// </summary> private void AddAuto() { while (true) { Random rd = new Random(); int num = rd.Next(0, 100); refreshTextBox(num); Display(num); } } /// <summary> /// 2.声明委托处理函数refreshTextBox /// </summary> /// <param name="num"></param> public void refreshTextBox(int num) { if (this.textBox1.InvokeRequired) { RefreshData rd = new RefreshData(refreshTextBox); if (this.textBox1.IsHandleCreated) { this.textBox1.Invoke(rd, num); } } else { this.textBox1.Text = num.ToString(); } } /// <summary> /// 2.声明委托处理函数Display /// </summary> /// <param name="num"></param> public void Display(int num) { if (this.progressBar1.InvokeRequired) { RefreshData rd = new RefreshData(Display); if (this.progressBar1.IsHandleCreated) { this.progressBar1.Invoke(rd, num); } } else { this.progressBar1.Value = num; } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { Application.Exit(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { Application.ExitThread(); } }}
- .NET WinForm编程Q&A系列(一)——多线程操作
- .NET WinForm编程Q&A系列(二)——反射机制
- .NET WinForm编程Q&A系列(三)——委托和事件
- C# winform编程 Q&A
- Q&A——动画(一)
- Q&A——资源管理(一)
- ASP.Net教程系列:多线程编程实战(一)
- 多线程学习系列:(八)Winform中多线程编程基础上
- ASP.NET温故而知新学习系列之ASP.NET多线程编程—.NET下的多线程编程临界区(八)
- ASP.NET温故而知新学习系列之ASP.NET多线程编程—.NET下的多线程编程应用程序域(七)
- Q&A——开发技巧(一)
- Q&A——资源制作(一)
- Q&A——内存管理(一)
- Q&A——资源加载(一)
- Q&A——图形渲染(一)
- Q&A——运行性能(一)
- Q&A——UI输入(一)
- Q&A——版本Bug(一)
- 函数自动调用
- 判断Android应用是否第一次运行之Preferences
- Xcode4.2中将Three20开源库导入到工程项目中
- 初学EXT
- 使用 Eclipse 调试 Compiere 的 JBoss 会计引擎
- .NET WinForm编程Q&A系列(一)——多线程操作
- c#下载问题
- ecplise调试 java.lang.NoClassDefFoundError异常解决方法
- C# Hashtable
- 在YII框架中运用smarty模板引擎
- Java性能小技巧
- js只能输入数字[价格等]
- Android中native进程内存泄露的调试技巧
- 我依然单身?