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

前言

当有大量.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();
        }
    }
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值