转载 C# 多线程编程实现进度条_小禹 css3实现圆环进度条

原文地址:[C#]多线程编程实现进度条作者:芝麻開花

在主winForm中有个进度条控件,点击某个button后,调用一个cs文件里的某个函数,这个函数用来遍历一个文件的,希望将函数遍历文件的进度反映到进度条上。

这里因为遍历文件的函数在另外一个类中,不在winForm类中,而遍历函数要对winForm中的progressbar进行操作,这就要用到委托了。

为什么要用到委托呢?

因为winform是主线程创建的,你用另外一个线程来调用它就可能会出现两个线程同时访问同一个资源的问题,这个时候很容易出现错误,比如A线程改变窗口的颜色为红色,B线程取窗口的颜色,如果这两个线程正好碰到一起,可能A略先于B,那么就是B取出来的红色,如果A略后于B,那么B取出来的就是窗口原来的颜色,而谁先谁后,这和CPU的繁忙度、时间片的轮转是相关的,是一种随机的情况,那么B取出来的颜色就不可靠了,因此为了避免这种状况采用委托,B线程向A线程发出委托,由A线程来完成取色工作,那么可以保证取色工作的稳定性,结果也可靠

Invoke,BeginInvoke,InvokeRequired

如果我们需要在另外一个线程里面对UI进行操作,我们需要一个操作UI界面的函数,还需要一个该函数的委托delegate,当然,我们可以自定义委托。

.net中有很多其他类型的委托,可以直接使用,不需要而外声明。例如:MethodInvoker和EventHandler,这两种类型委托的函数外观是固定的。

MethodInvoker是void Function()类型的委托,无参数。

EventHandler是void Function(object,EventArgs)类型的委托,这里参数类型和数量都是固定的。

这两种委托可以很方便的调用,但是缺乏灵活性。

请注意BeginInvoke前面的对象是this,也就是主线程。

再介绍Control.InvokeRequired,Control是所有控件的基类,对于这个属性MSDN的描述是:
   获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke方法,因为调用方位于创建控件所在的线程以外的线程中。
[转载][C#]多线程编程实现进度条_小禹 css3实现圆环进度条
该属性可用于确定是否必须调用Invoke 方法,当不知道什么线程拥有控件时这很有用。

也就是说通过判断InvokeRequired可以知道是否需要用委托来调用当前控件的一些方法。

下面来进行实例演练

首先在主Form中加入下面代码:

/// <summary>
     /// Form1 类
     /// </summary>
     public partial class Form1 : Form
     {
         public Form1()
         {
             InitializeComponent();
         }
         private void button1_Click(object sender, EventArgs e)
         {
             //用子线程工作
             new System.Threading.Thread(new System.Threading.ThreadStart(StartParse)).Start();
         }
         //开始parse file
         public void StartParse()
         {
             ParseFile pf = new ParseFile();
            pf.onParseProgress += new ParseFile.ParseProgress(parse_onParseProgress);            
            pf.Parse(txtMerchant.Text.Trim(), txtSave.Text.Trim());  //two textboxes
       }
         //同步更新UI
         private void parse_onParseProgress(int nTotal, int nCurrent)
        {
            if (this.InvokeRequired)
            {
                //ret = this.BeginInvoke(new ParseFile.ParseProgress(parse_onParseProgress), new object[] { nTotal, nCurrent });
                this.Invoke(new ParseFile.ParseProgress(parse_onParseProgress), new object[] { nTotal, nCurrent });
            }
            else
            {
                this.progressBar1.Maximum = nTotal;
                this.progressBar1.Value = nCurrent;
                lblProgress.Text = Convert.ToInt32(nCurrent / nTotal * 100).ToString() + "% Processing";
            }
        }

在遍历文件的类ParseFile中,我们加入委托和事件,用来反映现在的进度

class ParseFile
    {
        public delegate void ParseProgress(int nTotal, int nCurrent);
        public event ParseProgress onParseProgress;
public bool Parse(string strFileName, string strOutputFile)
        {
//get total lines of a file
int nTotal = 1;
                using (StreamReader reader1 = new StreamReader(strFileName))
                {
                    string strText = reader1.ReadToEnd();
                    MatchCollection mc = Regex.Matches(strText, "rn");
                    if (mc != null)
                        nTotal = mc.Count;
                }
//process each line
using (StreamReader reader = new StreamReader(strFileName))
                {   
                    int i=0;
                    while (reader.Peek() > 0)
                    {
                        string strLine = reader.ReadLine();
                        ParseOneLine(strLine);
                        i++;
 
                        if (onParseProgress != null)
                            onParseProgress(nTotal, i);
                    }
                }
}

这样就完成了在winform窗口不断更新进度条功能。

 

http://visionsky.blog.51cto.com/733317/368837

多线程基本知识点

新建一个线程(无参数,无返回值)

Thread th = new Thread(new ThreadStart(PrintName)); 
 
 public  void PrintName()    // 函数 
 { 
     //函数体 
 } 

这里一定注意ThreadStart中的函数是没有返回值和参数的

那么有参数时,就该如下:

Thread th = new Thread(new ParameterizedThreadStart(PrintName)); 
public  void PrintName(string name)    // 函数
{
 //函数体 
}

如果遇到又需要返回值,又需要参数的时候,就可以考虑用异步:

但是需要先申明个委托

public delegate string MethodCaller(string name);//定义个代理 
MethodCaller mc = new MethodCaller(GetName); 
string name = "my name";//输入参数 
IAsyncResult result = mc.BeginInvoke(name,null, null); 
string myname = mc.EndInvoke(result);//用于接收返回值 
 
public string GetName(string name)    // 函数
{
return name;
}

  

爱华网本文地址 » http://www.413yy.cn/a/25101014/223971.html

更多阅读

多线程的使用(Delphi) delphi多线程实例

TThread在Classes单元中声明,直接从TObject继承下来的,因为,它不是组件.TThread是个抽象类,所以不能创建TThread的实例,而只能创建其派生类的实例.利用TThread类来编写多线程应用程序的一般步骤如下:[步骤一]从TThread类派生出一个

linux 下多线程编程 linux下的多线程编程

共13章:第一章 线程基础multithreading可以被翻译成多线程控制。与传统的UNIX不同,一个传统的UNIX进程包含一个单线程,而多线程(MT)则把一个进程分成很多可执行线程,每一个线程都独立运行。阅读本章可以让你理解:Defining Multithreading T

php进程后台调用(多线程/进程) php 多进程与多线程

php进程后台调用http://blog.iyi.cn/start/2006/11/php_6.html这两天在研究php模拟多线程的问题,碰到一个问题就是无论exec、popen、还是proc_open都会造成等待,也就是阻塞式的调用,而我想要得是无阻塞的调用,让程序在后台执行就可以解

Linux下Qt多线程编程 linux下的多线程编程

作者:武汉华嵌技术部以下和大家分享Linux平台下Qt两种多线程编程的方式:1、使用Linux平台下的线程函数。以下是给出的代码片段://此处为连接信号和槽,通过Qt界面中两按钮来控制两个槽函数connect(pthred1start, SIGNAL(clicked()), this

声明:《转载 C# 多线程编程实现进度条_小禹 css3实现圆环进度条》为网友星汉西流赴尘行分享!如侵犯到您的合法权益请联系我们删除