sponsored links

asp.net用多线程实现进度条

C#是一门支持多线程的语言,因此线程的使用也是比较常见的。由于线程的知识在Win32编程的时候已经说得过多,所以在.Net中很少介绍这部分(可能.Net不觉得这部分是它所特有的)。
 
那么线程相关的问题大致有如下四类(这篇文章只讨论单线程、单线程与UI线程这两方面的问题)。
问题一,线程的基本操作,例如:暂停、继续、停止等;
问题二,如何向线程传递参数或者从中得到其返回值;
问题三,如何使线程所占用的CPU不要老是百分之百;
最后一个,也是问题最多的,就是如何在子线程来控制UI中的控件,换句话说,就是在线程中控制窗体某些控件的显示。
 
对于问题一,我不建议使用Thread类提供的SuspendResume以及Abort这三个方法,前两个有问题,好像在VS05已经屏蔽这两个方法;对于Abort来说,除了资源没有得到及时释放外,有时候会出现异常。如何做呢,通过设置开关变量来完成。
 
对于问题二,我不建议使用静态成员来完成,仅仅为了线程而破坏类的封装有些得不偿失。那如何做呢,通过创建单独的线程类来完成。
 
对 于问题三来说,造成这个原因是由于线程中进行不间断的循环操作,从而使CPU完全被子线程占有。那么处理此类问题,其实很简单,在适当的位置调用 Thread.Sleep(20)来释放所占有CPU资源,不要小看这20毫秒的睡眠,它的作用可是巨大的,可以使其他线程得到CPU资源,从而使你的 CPU使用效率降下来。
 
看完前面的三个问题的解释,对于如何做似乎没有给出一个明确的答案,为了更好地说明如何解决这三个问题,我用一个比较完整的例子展现给大家,代码如下。
http://blog.csdn.net/knight94/archive/2006/03/16/626584.aspx
http://blog.csdn.net/knight94/archive/2006/05/27/757351.aspx
 
首先说说,为什么不能直接在子线程中操纵UI呢。原因在于子线程和UI线程属于不同的上下文,换句比较通俗的话说,就好比两个人在不同的房间里一样,那么要你直接操作另一个房间里的东西,恐怕不行罢,那么对于子线程来说也一样,不能直接操作UI线程中的对象。
 
那么如何在子线程中操纵UI线程中的对象呢,.Net提供了Invoke和BeginInvoke这两种方法。简单地说,就是子线程发消息让UI线程来完成相应的操作。
 
这两个方法有什么区别,这在我以前的文章已经说过了,Invoke需要等到所调函数的返回,而BeginInvoke则不需要。
 
用这两个方法需要注意的,有如下三点:
第一个是由于InvokeBeginInvoke属于Control类型的成员方法,因此调用的时候,需要得到Control类型的对象才能触发,也就是说你要触发窗体做什么操作或者窗体上某个控件做什么操作,需要把窗体对象或者控件对象传递到线程中。
 
第二个,对于InvokeBeginInvoke接受的参数属于一个delegate类型,我在以前的文章中使用的是MethodInvoker,这是.Net自带的一个delegate类型,而并不意味着在使用Invoke或者BeginInvoke的时候只能用它。参看我给的第二篇文章(《如何弹出一个模式窗口来显示进度条》),会有很多不同的delegate定义。
 
最后一个,使用InvokeBeginInvoke有个需要注意的,就是当子线程在Form_Load开启的时候,会遇到异常,这是因为触发Invoke的对象还没有完全初始化完毕。处理此类问题,在开启线程之前显式的调用“this.Show();”,来使窗体显示在线程开启之前。如果此时只是开启线程来初始化显示数据,那我建议你不要使用子线程,用Splash窗体的效果可能更好。这方面可以参看如下的例子。
http://www.syncfusion.com/FAQ/WindowsForms/FAQ_c95c.aspx#q621q
 
线程的四个相关问题已经说完了,这篇文章只说了单线程,以及单线程与UI线程交互的问题。其中涉及到的方法不一定是唯一的,因为.Net还提供了其他类来扶助线程操作,这里就不一一罗列。至于多线程之间的同步,我会稍后专门写篇文章进行描述。
如何弹出一个模式窗口来显示进度条
最近看了好多人问这方面的问题,以前我也写过一篇blog,里面说了如何在子线程中控制进度条。但目前大多数环境,需要弹出模式窗口,来显示进度条,那么只需要在原先的基础上稍作修改即可。
 
首先是进度条窗体,需要在上面添加进度条,然后去掉ControlBox。除此外,还要增加一个方法,用来控制进度条的增加幅度,具体如下:
    ///<summary>
    /// Increase process bar
    ///</summary>
    ///<param name="nValue">the value increased</param>
    ///<returns></returns>
    public bool Increase( int nValue )
    {
        if( nValue > 0 )
        {
            if( prcBar.Value + nValue < prcBar.Maximum )
            {
                prcBar.Value += nValue;
                return true;
            }
            else
            {
                prcBar.Value = prcBar.Maximum;
                this.Close();
                return false;
            }
        }
        return false;
    }
 
接着就是主窗体了,如何进行操作了,首先需要定义两个私有成员,一个委托。其中一个私有成员是保存当前进度条窗体对象,另一个是保存委托方法(即增加进度条尺度),具体如下:
    private frmProcessBar myProcessBar = null;
    private delegate bool IncreaseHandle( int nValue );
    private IncreaseHandle myIncrease = null;
 
接着要在主窗体中提供函数来打开进度条窗体,如下:
    ///<summary>
    /// Open process bar window
    ///</summary>
    private void ShowProcessBar()
    {
        myProcessBar = new frmProcessBar();
 
        // Init increase event
        myIncrease = new IncreaseHandle( myProcessBar.Increase );
        myProcessBar.ShowDialog();
        myProcessBar = null;
    }
 
那么现在就可以开始创建线程来运行,具体如下:
    ///<summary>
    /// Sub thread function
    ///</summary>
    private void ThreadFun()
    {
        MethodInvoker mi = new MethodInvoker( ShowProcessBar );
        this.BeginInvoke( mi );
 
        Thread.Sleep( 1000 );//Sleep a while to show window
 
        bool blnIncreased = false;
        object objReturn = null;
        do
        {
            Thread.Sleep( 50 );
            objReturn = this.Invoke( this.myIncrease,
                new object[]{ 2 } );
            blnIncreased = (bool)objReturn ;
        }
        while( blnIncreased );
    }
      
       注意以上,在打开进度条窗体和增加进度条进度的时候,一个用的是BeginInvoke,一个是Invoke,这里的区别是BeginInvoke不需要等待方法运行完毕,而Invoke是要等待方法运行完毕。还有一点,此处用返回值来判断进度条是否到头了,如果需要有其他的控制,可以类似前面的方法来进行扩展。
 
启动线程,可以如下:
    Thread thdSub = new Thread( new ThreadStart( ThreadFun ) );
    thdSub.Start();
 
这样,一个用模式打开进度条窗体就做完了。
 
Tags:
  • 使用ASP.NET Atlas编写显示进度条控件
    使用ASP.NET Atlas编写显示进度条控件
    使用ASP.NET Atlas编写显示进度条控件     当后台在进行某些长时间的操作时,如果能在页面上提供一个显示真实进度的进度条,而不是让用户不知情的等待或是从前的那些简单的估计,将是一个非常难得的出彩之处.现在使用ASP.NET Atlas完全有可能做到这些.这篇文章将讨论如何完成这一功能并介绍一些有关Atlas客户端控件开发的基本概念.您同时可以在这 ...
  • ExtJS+ASP.NET实现真实的进度条显示服务器端长时间操作的进度
    ExtJS+ASP.NET实现真实的进度条显示服务器端长时间操作的进度
    ExtJS+ASP.NET实现真实的进度条显示服务器端长时间操作的进度 当服务器端执行一个长时间的操作时,页面上如何显示一个反应真实的进度条,报告服务器端执行耗时操作的进度,而不是让用户永远等待,这对用户来说是非常有用的,能够有效提高用户体验(参见<用户体验这点事儿>).这篇文章使用AJAX,ASP.NET和ExtJS实现这个功能. 实现过程大概 ...
  • asp.net单文件带进度条上传的解决方案
    asp.net单文件带进度条上传的解决方案
    本文介绍的asp.net单文件带进度条上传,不属于任务控件,也不是flash类型的上传,完全是asp.net.js.css实现上传,需要的朋友可以参考下最近做项目中遇到很多问题,比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的ASP.NET实现进度条上传(可能是我没找到),下面我来跟大家分享一下我实现的这个程序.首先看下界面效果,当然你可以完全修 ...
  • ASP.NET制做Web实时进度条
     网上已经有很多Web进度条的例子,但是很多都是估算时间,不能正真反应任务的真实进度.我自己结合多线程和ShowModalDialog制做了一个实时进度条,原理很简单:使用线程开始长时间的任务,定义一个Session,当任务进行到不同的阶段改变Session的值,线程开始的同时使用ShowModalDialog打开一个进度条窗口,不断刷新这个窗口获取Sess ...
  • C#编程总结四多线程应用进度条的编程问题——转自http://www.cnblogs.com/yank/p/3232955.html
    C#编程总结四多线程应用进度条的编程问题——转自http://www.cnblogs.com/yank/p/3232955.html
    多线程应用 多线程应用很广泛,简单总结了一下:1)不阻断主线程,实现即时响应,由后台线程完成特定操作2)多个线程,完成同类任务,提高并发性能3)一个任务有多个独立的步骤,多个线程并发执行各子任务,提高任务处理效率下面我们通过几个小例子做简单介绍.1.进度条分析:页面动态刷新,主页面正常可操作.我们通过后台线程来实现进度条.首先,创建Winform页面,然后拖 ...