c# winform多线程的小例子

时间:2023-01-05 07:11:44 

c# winform多线程的小例子

在文本框中输入一个数字,点击开始累加按钮,程序计算从1开始累计到该数字的结果。因为该累加过程比较耗时,如果直接在UI线程中进行,那么当前窗口将出现假死。为了有更好的用户体验,程序启动一个新的线程来单独执行该计算,然后每隔200毫秒读取一次累加结果,并把结果显示到文本框下方的label控件中。同时,程序支持取消操作,点击取消累计按钮,程序将取消累加操作,并把当前累加值显示到label中。为了方便后面的描述,我把UI线程称作主线程,把执行累加计算的线程称作工作者线程。该过程有两个关键点:

1:如何在工作者线程中访问主线程创建的控件;

2:如何取消比较耗时的计算;

为了便于在工作者线程中调用累加过程,我把它写成一个单独方法,如下:


/// <summary>
        /// 从1累加到指定的值,为了让该方法支持取消操作所以需要CancellationToken参数
        /// </summary>
        /// <param name="countTo">累加到的指定值</param>
        /// <param name="ct">取消凭证</param>
        private void CountTo(int countTo, CancellationToken ct) {
            int sum = 0;
            for (; countTo > 0; countTo--) {
                if (ct.IsCancellationRequested) {
                    break;
                }
                sum += countTo;
                //Invoke方法用于获得创建lbl_Status的线程所在的上下文
                this.Invoke(new Action(()=>lbl_Status.Text = sum.ToString()));               
                Thread.Sleep(200);
            }
        }


该方法就是用于累加数字,它有两个需要注意的地方

1:方法需要传递一个CancellationToken参数,用于支持取消操作(《clr via c# 3版》中把这种方式称作协作式取消,也就是说某一个操作必须支持取消,然后才能取消该操作);

2:为了允许工作者线程访问主线程创建的lbl_Status控件,我在该线程中使用this.Invoke方法。该方法用于获得主线程所创建控件的访问权。它需要一个委托作为参数,在该委托中我们可以定义对lbl_Status的操作。例如在上例中我就是把当前的累加结果赋给lbl_Status的Text属性。

然后我们看一下如何在一个共走着线程中执行计算耗时的操作,也就是“开始累加”按钮的操作:


private void btn_Count_Click(object sender, EventArgs e)
        {
            _cts = new CancellationTokenSource();
            ThreadPool.QueueUserWorkItem(state=>CountTo(int.Parse(txt_CountTo.Text),_cts.Token));
        }

我使用线程池线程来执行该操作,之所以使用线程池线程而不是自己的Threading对象,是因为线程池默认已经为我们创建好了一些线程,从而省去创建新线程造成的一些列资源消耗,同时,完成计算任务后该线程池线程自动回到池中等待下一个任务。我把_cts作为一个成员变量,声明如下:


private CancellationTokenSource _cts;

它需要引入using System.Threading;命名空间。

取消操作更加简单,代码如下:


private void btn_Cancel_Click(object sender, EventArgs e)
        {
            if (_cts != null)
                _cts.Cancel();
        }

这样我们就完成了在winform中使用多线程的例子,同时该例子支持取消操作。完整代码如下:


using System;
using System.Threading;
using System.Windows.Forms;

namespace WinformApp
{
    public partial class Form1 : Form
    {
        private CancellationTokenSource _cts;
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 从1累加到指定的值,为了让该方法支持取消操作所以需要CancellationToken参数
        /// </summary>
        /// <param name="countTo">累加到的指定值</param>
        /// <param name="ct">取消凭证</param>
        private void CountTo(int countTo, CancellationToken ct) {
            int sum = 0;
            for (; countTo > 0; countTo--) {
                if (ct.IsCancellationRequested) {
                    break;
                }
                sum += countTo;
                //Invoke方法用于获得创建lbl_Status的线程所在的上下文
                this.Invoke(new Action(()=>lbl_Status.Text = sum.ToString()));

                Thread.Sleep(200);
            }
        }

        private void btn_Count_Click(object sender, EventArgs e)
        {
            _cts = new CancellationTokenSource();
            ThreadPool.QueueUserWorkItem(state=>CountTo(int.Parse(txt_CountTo.Text),_cts.Token));
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            if (_cts != null)
                _cts.Cancel();
        }

        private void btn_Pause_Click(object sender, EventArgs e)
        {

        }

    }
}

标签:winform,多线程
0
投稿

猜你喜欢

  • Android进阶事件分发机制解决事件冲突

    2021-08-22 06:12:34
  • C#实现密码验证与输错密码账户锁定

    2022-04-05 13:22:22
  • Android 中 SwipeLayout一个展示条目底层菜单的侧滑控件源码解析

    2022-03-10 14:25:33
  • Java保留两位小数的几种写法总结

    2022-04-19 06:53:06
  • VS2019配置opencv详细图文教程和测试代码的实现

    2023-07-17 13:49:31
  • OpenGL绘制Bezier曲线的方法

    2023-11-01 03:59:30
  • 基于JSON实现传输byte数组过程解析

    2021-11-23 05:07:21
  • 如何使用java修改文件所有者及其权限

    2023-11-16 09:35:53
  • Java Swing组件文件选择器JFileChooser简单用法示例

    2021-09-23 21:00:34
  • Java实现抢红包功能

    2021-08-05 07:47:58
  • Spring Security+JWT简述(附源码)

    2022-10-16 11:57:51
  • 详解C#之委托

    2021-12-12 00:17:49
  • springboot v2.0.3版本多数据源配置方法

    2023-07-27 06:37:57
  • ionic App 解决android端在真机上tab处于顶部的问题

    2022-05-11 21:56:57
  • Android编程之ActionBar Tabs用法实例分析

    2021-11-08 08:49:26
  • (starters)springboot-starter整合阿里云datahub方式

    2023-03-12 06:28:16
  • C#实现观察者模式(Observer Pattern)的两种方式

    2023-06-20 21:05:18
  • C# 如何调用C++ dll string类型返回

    2023-01-31 02:27:55
  • Recyclerview添加头布局和尾布局、item点击事件详解

    2022-04-19 12:38:12
  • Java中数组转List的三种方法与对比分析

    2023-03-27 08:51:03
  • asp之家 软件编程 m.aspxhome.com