.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();        }    }}




原创粉丝点击