先看效果

在文本框中输入一个数字,点击开始累加按钮,程序计算从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中使用多线程的例子,同时该例子支持取消操作。完整代码如下:

View Code

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){}}
}

转载于:https://www.cnblogs.com/jjhe369/archive/2013/04/14/3019662.html

一个winform中多线程的例子相关推荐

  1. c#:winform中多线程的使用

    最近由于在做一些demo之类的小测试,所以winform程序用的多了点.但是在使用的过程中发现在winform中对多线程的应用的相关知识变得模糊,所以就多看了相关知识点并整理测试了部分,记录相关内容, ...

  2. Winform中使用进度条的一个例子

    因为在winform程序中,UI线程负责界面相关的工作. Winform中使用进度条的方法有很多,可以直接创建一个新的线程Thread执行耗时的方法:也可以使用线程池. 例如: //使用线程池异步执行 ...

  3. [转] c#中 多线程访问winform控件

    原文 c#中多线程访问winform控件的若干问题小结 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来解决这个问题,下面我将详细的 ...

  4. 用python中函数输出杨辉三角_用Python输出一个杨辉三角的例子

    这篇文章主要介绍了用Python和erlang输出一个杨辉三角的例子,同时还提供了一个erlang版杨辉三角,需要的朋友可以参考下 关于杨辉三角是什么东西,右转维基百科:杨辉三角 稍微看一下直观一点的 ...

  5. Winform中实现新增和更新共用一个页面的示例流程

    场景 Winform中对某个表的数据查询出来,数据放在DataTable中,并将其显示在DataGrdiView中. 点击新增和编辑时打开的是同一个页面. 打开页面加载所有数据并显示 点击新增 点击编 ...

  6. 多进程/多线程同时向一个文件中写入日志如何避免冲突?

    写入文件时都会调用函数 write,由于所有的系统调用都是原子的,所以该函数可以保证进程或者线程写入数据的过程中不会被其他进程或者线程打扰,即:数据中间插入别的进程的数据. 另外一个问题,由于 wri ...

  7. java notify视频_一个很好的小例子来演示java中的wait()和notify()方法

    任何人都可以在 java中为我提供一个很好的小例子演示wait()和notify()功能.我尝试使用下面的代码,但它没有显示我的预期. public class WaitDemo { int i = ...

  8. c#点击按钮调出另一个窗体_在类库或winform项目中打开另一个winform项目窗体的方法...

    本文实例讲述了在类库或winform项目中打开另一个winform项目窗体的方法.分享给大家供大家参考.具体如下: 一.问题: 假设类库或winform项目为A,另一个winform项目为B.那麽在A ...

  9. WinForm中新开一个线程操作窗体上的控件(跨线程操作控件)GOOD

    http://www.cnblogs.com/joey0210/p/3450379.html 最近在做一个winform的小软件(抢票的...).登录窗体要从远程web页面获取一些数据,为了不阻塞登录 ...

  10. c语言字符串的一个简单例子,把一个字符串中的小写字母改成大写字母

    把一个字符串中小写字母改成大写字母,利用toupper()函数,这个函数定义在 ctype.h 头文件中 #include <stdio.h> #include <ctype.h&g ...

最新文章

  1. linux gcc 内联汇编入门
  2. Oracle 数据库修改配置文件sga_target参数的值,sga_target值太小导致数据库服务起不来问题解决,调大sga_target参数方法
  3. redis 哨兵_Redis哨兵的配置和原理
  4. 【测评】海康EliteX---全球首款USB4.0移动固态硬盘,硬盘黑科技,移动闪电侠
  5. 疫情期间,千万级系统宕机N次,老板撂下狠话:没法把性提升10倍,全员解雇!...
  6. unwind neo4j_Neo4j 2.1:传递节点ID与UNWIND
  7. javafx中的tree_JavaFX中的塔防
  8. 一波三折,这些离国出走的品牌又回来了!
  9. idea中下载插件超时_完美解决idea无法搜索下载插件的问题
  10. 【实践】汽车之家推荐系统排序算法迭代之路.pdf(附下载链接)
  11. java使double保留两位小数
  12. 科大讯飞携手华南理工,成立脑机接口公司,注册资本4000万
  13. 如何调节idea jvm的最大内存_那个小白还没搞懂内存溢出,只能用案例说给他听了
  14. 服务器互相备份不同步_94爱分享拍了拍你,这款好用的数据同步备份软件千万不要错过!...
  15. Flex Builder教程
  16. dx逆向建模步骤_产品温度的逆向建模的系统和方法与流程
  17. 学计算机穿格子衬衫的男人,教你成为穿格子衬衫的帅气理工男
  18. C#登录语音提醒操作
  19. [Python模块]根据姓名笔画数排序
  20. SparkEnv源码解读

热门文章

  1. Struts 2.0 入门
  2. 《软件工程(第4版?修订版)》—第2章2.7节本章对单个开发人员的意义
  3. 企业如何选择最佳的SSL
  4. hive启动debug问题
  5. 原创Netty学习系列导航
  6. ARC070D No Need
  7. 高德地图上覆盖物polygon方法的使用
  8. 预检请求会让服务器性能,如何避免“预检请求”?
  9. php查询mysql表里的数据_PHP连接Mysql数据库读取表格数据
  10. java web gradle_java web使用gradle配置详情