当前位置:编程学习 > asp >>

.NET WinForm编程Q&A系列(一)——多线程操作

前言
当有大量.NET程序员进入这个领域后,利用"即见即所得"的机制我们可以快速的开发出了很多应用程序,但是随着深入这个领域,我们会发现,有UI的设计往往不能开发出比较理想的系统原型,甚至有1~3年经验的.NET程序员仍然不能理解诸多概念,如多线程、反射、**机制,包括我本人也是如此。所以《.NET WinForm编程Q&A系列》就是基于本人的理解能力进行整理。整个系列都会包括如下内容:
【背景】重点提出WinForm编程中的问题以及相关晦涩的概念;
【概念】教科书或者百度百科关于这些问题以及概念的介绍,我估计大多数程序员不愿意接受这种方式;
【需求】对应这些问题以及概念,本人提出了一个系统实例,并希望借助这个实例可以对背景提出的若干问题进行求解,也让大家对概念进行一个梳理;
【实战】详细介绍实例的实现过程,当然针对实例,会有很多的解决方案,本文所提出的实战过程仅仅是其中一种。
【备注】欢迎大家提出宝贵意见。
背景
如何理解并应用多线程操作?
概念
1、多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的;
2、使用线程可以把占据时间长的程序中的任务放到后台去处理;
3、在本质上和结构来说,.NET是一个多线程的环境。有两种主要的多线程方法是.NET所提倡的:使用ThreadStart来开始你自己的进程,直接的(使用ThreadPool.QueueUserWorkItem)或者间接的(比如Stream.BeginRead,或者调用BeginInvoke)使用ThreadPool类。一般来说,你可以"手动"为长时间运行的任务创建一个新的线程,另外对于短时间运行的任务尤其是经常需要开始的那些,进程池是一个非常好的选择。进程池可以同时运行多个任务,还可以使用框架类。对于资源紧缺需要进行同步的情况来说,它可以限制某一时刻只允许一个线程访问资源。这种情况可以视为给线程实现了锁机制。线程的基类是System.Threading。所有线程通过CLI来进行管理。
需求
控件内容的定时变更,每隔1秒,文本控件将显示一个随机数(0,100),进度条进行显示。
 
如下图所示。
 
 
实战
1、根据需求中提到的系统要求,初级的程序员会快速的写出方案,如下所示:
 
[csharp]  
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、一旦运行后,发现界面动不了,于是又考虑用计数器实现,如下:
[csharp] 
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.声明委托。
 
[csharp]  
/// <summary>  
/// 1.声明委托  
/// </summary>  
/// <param name="num"></param>  
delegate void RefreshData(int num);  
delegate void AutoRefresh();  
2.声明委托处理函数(判断是主线程控制UI控件,还是Invoke(多线程)控制UI控件)。
[csharp] 
/// <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()。
[csharp]  
//3.声明一个线程实例  
Thread refreshThread = new Thread(new ThreadStart(ar));  
4.开启该线程。
[csharp]  
//4.开启该线程  
refreshThread.Start();  
5.定义该线程函数,欲控制UI控件,则调用第2步的委托处理函数,他将自己判断选择用Invoke。
6.定义Invoke需要调用的函数
[csharp]  
/// <summary>  
/// 6.定义Invoke需要调用的函数  
/// </summary>  
private void AddAuto()  
{  
    while (true)  
    {  
        Random rd = new Random();  
        int num = rd.Next(0, 100);  
        refreshTextBox(num);  
        Display(num);  
    }  
}  
备注
代码全集如下:
[csharp]  
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  
补充:Web开发 , ASP.Net ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,