C# WinForm实现多线程 小程序

最近想用WinForm完成一个多线程的开发,奈何以前都没有接触过多线程的东西,让人头大,在脚本之家看到一个很好的小程序例子,这里自己做了小小的改动和注释,在这里发出来大家一起学习一下。
首先看一下这个小程序可以完成的功能:
在文本框中输入一个数字,点击开始累加按钮,程序从1开始累计到该数字的结果。由于累加的过程时间比较耗时,如果直接在主线程中计算,窗口会出现卡死情况(即不能移动),为了能有更好的用户体验,程序启动一个新的线程来单独执行该计算,然后每隔200毫秒读取一次累加结果,并把结果显示到文本框下方的label控件中。
同时,程序支持取消操作,点击取消累计按钮,程序将取消累加操作,并把当前累加值显示到label中。为了方便后面的描述,把执行累加计算的线程称作工作者线程。该过程有两个关键点:1:如何在工作者线程中访问主线程创建的控件; 2:如何取消比较耗时的计算;
命名空间:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

代码部分:

namespace 多线程练习
{   
    public partial class Form1 : Form
    {   
        CancellationTokenSource cts = new CancellationTokenSource();
        public Form1()
        {   
            InitializeComponent();
        }

        //将累加过程封装程一个方法,此方法就是用于累加数字,它有两个需要注意的地方
        //1:从1累加到指定的值,为了让该方法支持取消操作,所以需要CancellationT参数,用于支持取消操作
        //2:为了允许工作者线程访问主线程创建的label控件,在该线程中使用this.Invoke方法。该方法用于获得主线程所创建控件的访问权。
        //重要:this.Invoke方法需要一个委托作为参数,在改委托中我们可以定义对label的操作。例如可以把当前累加的结果赋值给label的text属性。
        private void CountTo(int countTo, CancellationToken ct)
        {   
            int sum = 0;
            for (; countTo > 0; countTo--)
            {
                if (ct.IsCancellationRequested)
                {
                    break;
                }
                sum += countTo;
                //Invoke方法用于获得创建label的线程所在的上下文
                this.Invoke(new Action(() => label1.Text = sum.ToString()));

                Thread.Sleep(200);
            }
        }
        //开始累加按钮:
        //使用线程池线程来执行该操作,之所以使用线程池线程而不是自己的Threading对象,
        //因为线程池默认已经为我们创建好了一些线程,从而省去创建新线程造成的一些列资源消耗,同时,完成计算任务后该线程池线程自动回到池中等待下一个任务。
        private void button2_Click(object sender, EventArgs e)
        {   
            ThreadPool.QueueUserWorkItem(state => CountTo(int.Parse(textBox1.Text), cts.Token));
        }

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

实际效果:
在这里插入图片描述
今天的分享就到此结束了
附上资源来源:https://www.jb51.net/article/35526.htm
感觉有用的请点个赞支持一下谢谢!

以下是一个简单的 C# WinForm 多线程的例子,它使用了 BackgroundWorker 组件来实现多线程处理任务: 1. 在 WinForm 窗体中添加一个按钮和一个 Label 控件。 2. 双击按钮控件,打开 Click 事件处理程序。 3. 在事件处理程序中添加以下代码: ```csharp private void button1_Click(object sender, EventArgs e) { // 启动后台任务 backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // 模拟一个长时间运行的任务 for (int i = 0; i < 100; i++) { Thread.Sleep(100); backgroundWorker1.ReportProgress(i); } } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // 更新 Label 控件的显示内容 label1.Text = $"已完成 {e.ProgressPercentage}%"; } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // 显示任务完成提示 MessageBox.Show("任务已完成!"); } ``` 4. 在窗体的构造函数中,添加以下代码: ```csharp public Form1() { InitializeComponent(); // 启用支持多线程的控件样式 Control.CheckForIllegalCrossThreadCalls = false; // 配置 BackgroundWorker 组件 backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.WorkerSupportsCancellation = false; } ``` 以上代码的作用如下: - 当用户单击按钮时,启动后台任务; - 后台任务模拟一个长时间运行的任务,每隔一段时间更新一次进度; - 当进度更新时,更新 Label 控件的显示内容; - 当任务完成时,弹出一个提示框。 需要注意的是,在多线程应用程序中,UI 线程和后台线程是分别运行的,不能直接访问 UI 控件。为了避免出现访问冲突,可以启用支持多线程的控件样式,并使用 Invoke 或 CheckForIllegalCrossThreadCalls 属性来解决这个问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值