// 通过创建委托解决传递参数问题
private void _btnRun_Click( object sender, System.EventArgs e )
{
RunTaskDelegate runTask = new RunTaskDelegate( RunTask );

// 委托同步调用方式
runTask( Convert.ToInt16( _txtSecond.Value ) );
}

//通过创建委托解决传递参数问题,通过委托的异步调用消除用户界面线程的阻塞问题
private void _btnRun_Click( object sender, System.EventArgs e )
{
RunTaskDelegate runTask = new RunTaskDelegate( RunTask );

// 委托异步调用方式
runTask.BeginInvoke( Convert.ToInt16( _txtSecond.Value ), null, null );
}

多线程安全

到这里为止,我们已经解决了长任务的难题和传递参数的困扰。但是我们真的解决了全部问题吗?回答是否定的。

我们知道 Windows 编程中有一个必须遵守的原则,那就是在一个窗体创建线程之外的任何线程中都不允许操作窗体。

我们上面的程序就是存在这样的问题:工作线程是在 ShowProgress 方法中修改了用户界面的进度条的属性。那为什么程序运行没有出现问题,运行正常呢?

没有发生问题是因为是现在的Windows XP操作系统对这类问题有非常健壮的解决方法,让我们避免了问题的发生。但是我们现在的程序不能保证在其他的操作系统能够运行正常!

  真正的解决方法是我们能够认识到问题所在,并在程序中加以避免。

  如何避免多线程的窗体资源访问的安全问题呢?其实非常简单,有两种方法:

一种方法就是不管线程是否是用户界面线程,对用户界面资源的访问统一由委托完成;

另一种方法是在每个 Windows Forms 用户界面类中都有一个 InvokeRequired
属性,它用来标识当前线程是否能够直接访问窗体资源。我们只需要检查这个属性的值,只有当允许直接访问窗体资源时才直接访问相应的资源,否则,就需要通过
委托进行访问了。

  采用第一种安全的方法的代码片断如下:

// 显示进度条的委托声明
delegate void ShowProgressDelegate( int totalStep, int currentStep );

// 显示进度条
void ShowProgress( int totalStep, int currentStep )
{
_Progress.Maximum = totalStep;
_Progress.Value = currentStep;
}

// 执行任务的委托声明
delegate void RunTaskDelegate( int seconds );

// 执行任务
void RunTask( int seconds )
{
ShowProgressDelegate showProgress = new ShowProgressDelegate( ShowProgress );

// 每 1 / 4 秒 显示进度一次
for( int i = 0; i < seconds * 4; i++ )
{
Thread.Sleep( 250 );

// 显示进度条
this.Invoke( showProgress, new object[] { seconds * 4, i + 1 } );
}
}

采用第二种安全的方法的代码片断如下:

// 显示进度条的委托声明
delegate void ShowProgressDelegate( int totalStep, int currentStep );

// 显示进度条
void ShowProgress( int totalStep, int currentStep )
{
if( _Progress.InvokeRequired )
{
ShowProgressDelegate showProgress = new ShowProgressDelegate( ShowProgress );

// 为了避免工作线程被阻塞,采用异步调用委托
this.BeginInvoke( showProgress, new object[] { totalStep, currentStep } );
}
else
{
_Progress.Maximum = totalStep;
_Progress.Value = currentStep;
}
}

// 执行任务的委托声明
delegate void RunTaskDelegate( int seconds );

// 执行任务
void RunTask( int seconds )
{
// 每 1 / 4 秒 显示进度一次
for( int i = 0; i < seconds * 4; i++ )
{
Thread.Sleep( 250 );

// 显示进度条
ShowProgress( seconds * 4, i + 1 );
}
}

至此,我们用了几个示例说明了如何执行长任务、如何通过多线程异步处理任务进度的显示并解决了多线程的安全性等问题。希望能够给大家对理解多线程编程、委托的使用、异步调用等方面提供一些帮助,也希望能和大家进行进一步的沟通和交流。

C# 通过线程来控制进度条(转)--讲解多线程对界面的操作的更多相关文章

  1. js控制进度条到达100%跳转界面一

    进度条一般在手机上用到的比较广泛,刚好最近的项目也是一直在做手机站,这个特效是手机端的一个界面,现在我把改成pc端了,进度条的快慢速度和样式可自行调节,改动也是很方便的,不多说,看代码: <st ...

  2. C# 通过委托控制进度条以及多线程更新控件

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. 【Winform】使用BackgroundWorker控制进度条显示进度

    许多开发者看见一些软件有进度条显示进度,自己想弄,项目建好后发现并没有自己想象中的那么简单...看了网上很多教程后,写了一个小Demo供网友们参考~~,Demo的网址:http://pan.baidu ...

  4. 使用timer控件控制进度条

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  5. js控制进度条数据

    <style><!-- #time{ width:500px; height: 20px; background: red; border-radius: 10px; } --> ...

  6. android 对话框中的进度条 (ProgressDialog)

    from:http://byandby.iteye.com/blog/817214 显然要定义对话框进度条就要用ProgressDialog,首先我们需要创建ProgressDialog对象,当然这里 ...

  7. 使用线程新建WPF窗体(公用进度条窗体)

    使用线程新建窗体 项目中需要一个公用的进度条窗体.大家知道在wpf中,有两个线程,一个是UI线程,另一个是监听线程(一直监听用户的输入).如果我们后台有阻塞UI线程的计算存在,那么界面上的比如进度条什 ...

  8. C#使用进度条,并用线程模拟真实数据 ProgressBar用法(转)

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  9. Android——ProgressDialog 进度条对话框

    public class ProgressDialogActivity extends Activity {    private Button btn_large_pd, btn_horizonta ...

随机推荐

  1. Ansible安装配置Nginx

    一.思路 现在一台机器上编译安装好nginx.打包,然后在用ansible去下发 cd /etc/ansible 进入ansible配置文件目录 mkdir roles/{common,install ...

  2. 按Right-BICEP的测试用例

    测试方法:Right-BICEP 测试计划 1.Right-结果是否正确? 2.B-是否所有的边界条件都是正确的? 3.P-是否满足性能要求? 4.结果是否有符合要求的20道题目? 5.所得到的最大数 ...

  3. svn 安装 、使用(1)

    写在开头: 虽然网络极大的方便了我们查找答案,而且有很多人写各样的博客.但每个人在实际中的情况不一样,遇到的问题也不一样,大牛们会把步骤写的很简单,可能真的是怕麻烦,但显然就有一些东西已经不适合一部分 ...

  4. centos启动流程[转]

    启动流程概览 在硬件驱动成功后,Kernel 会主动呼叫 init 程序,而 init 会取得 run-level 资讯: init 运行 /etc/rc.d/rc.sysinit 文件来准备软件运行 ...

  5. Teaching Your Computer To Play Super Mario Bros. – A Fork of the Google DeepMind Atari Machine Learning Project

    Teaching Your Computer To Play Super Mario Bros. – A Fork of the Google DeepMind Atari Machine Learn ...

  6. JSBinding / Gen Bindings

    Classes in JSBindingSettings.classes array will be exported to JavaScript. There are already many cl ...

  7. 锁_rac环境kill锁表会话后出现killed状态(解决)

    原创作品,出自 "深蓝的blog" 博客,深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/46876961 ra ...

  8. 虚拟化之vmware DirectPath I/O

    首先Intel这边,必须CPU支持VT-D,基本就是i5/i7的型号,而且部分i5中低端型号还不支持,带K的不支持.同时主板要开启VT-D支持,这些从775时代开始就有了,所以型号搭配复杂.AMD那边 ...

  9. unity, ugui input field

    ugui Input Field,获取输入的字符串. 错误方法: string content=inputField.FindChild("Text").text; 这样得到的是输 ...

  10. Google Proposes to Enhance JSON with Jsonnet

    Google has open sourced Jsonnet, a configuration language that supersedes JSON and adds new features ...