加入收藏 | 设为首页 | 会员中心 | 我要投稿 北几岛 (https://www.beijidao.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

C#中的线程三 (结合ProgressBar学习Control.BeginInvoke)

发布时间:2021-05-21 05:22:11 所属栏目:大数据 来源: https://www.jb51.cc
导读:C#中的线程三(结合ProgressBar学习Control.BeginInvoke) ? ? 本篇继上篇转载的关于Control.BeginInvoke的论述之后,再结合一个实例来说明Cotrol.BeginInvoke的功能 ? ? 通过前面2篇的学习应该得出以下结论 1、Delegate.BeginInvoke中执行的方法是异步的 1 pu

C#中的线程三(结合ProgressBar学习Control.BeginInvoke)

?

? 本篇继上篇转载的关于Control.BeginInvoke的论述之后,再结合一个实例来说明Cotrol.BeginInvoke的功能

? ? 通过前面2篇的学习应该得出以下结论

1、Delegate.BeginInvoke中执行的方法是异步的

1 public @H_404_18@static @H_404_18@void@H_404_18@ Start2()
@H_404_18@2 @H_404_18@ {
@H_404_18@3    Console.WriteLine("main thread:{0},{1},{2}"@H_404_18@,Thread.CurrentThread.CurrentCulture,Thread.CurrentThread.Name,Thread.CurrentThread.ManagedThreadId);
@H_404_18@4    @H_404_18@//@H_404_18@DoSomethingDelegate del = new DoSomethingDelegate(Method1);
@H_404_18@5     DoSomethingDelegate del =@H_404_18@ Method1;
@H_404_18@6     del.BeginInvoke(this is delegate method",@H_404_18@null,@H_404_18@null)    Console.WriteLine(main thread other things...);
@H_404_18@7  }

相当于另开了一个线程来执行Method1方法

2. 如果在UI线程里做Control.BeginInvoke,执行到的方法并没有做到异步

@H_404_18@private @H_404_18@void butBeginInvoke_Click(@H_404_18@object@H_404_18@ sender,EventArgs e) {
@H_404_18@2    @H_404_18@A代码段.......
@H_404_18@3    @H_404_18@this.BeginInvoke(@H_404_18@new@H_404_18@ BeginInvokeDelegate(BeginInvokeMethod));
@H_404_18@B代码段......
@H_404_18@5 }

也就是说此段代码里,BeginInvokeMethod方法并没有异步执行到,也即没有新开线程做BeginInvokeMethod这个方法

3.如果要让Control.BeginInvoke做到异步,需要在UI线程里新开一个线程,在这个新开的线程里调用Control.BeginInvoke,才能有异步功能

@H_404_18@ 1 @H_404_18@private@H_404_18@ Thread beginInvokeThread;
@H_404_18@ 2 @H_404_18@delegate @H_404_18@ beginInvokeDelegate();
@H_404_18@ 3 @H_404_18@ StartMethod(){
@H_404_18@ 4    @H_404_18@C代码段......
@H_404_18@ 5    Control.BeginInvoke(@H_404_18@ beginInvokeDelegate(beginInvokeMethod));
@H_404_18@ 6   @H_404_18@D代码段......
@H_404_18@ 7 @H_404_18@}
@H_404_18@ 8 @H_404_18@ beginInvokeMethod(){
@H_404_18@ 9   @H_404_18@E代码段
@H_404_18@10 @H_404_18@11 @H_404_18@12    @H_404_18@13    beginInvokeThread = @H_404_18@new Thread(@H_404_18@ ThreadStart(StartMethod));
@H_404_18@14 @H_404_18@   beginInvokeThread .Start();
@H_404_18@15    @H_404_18@16 }

有了上面的理解,我们结合实例来继续学习Control.BeginInvoke

?二、ProgressBar的使用

???? WinForm里有这样一种场景,就是一边处理数据,一边用ProgressBar显示进度,要做出这种功能来如果还是用单线程那种普通的思路,按顺序编码下来,进度条就会从0突然变成100,失去了进度功能。

1.假如我们现在要读取大量数据, 需要用ProgressBar来显示进度,我们先定义一个类,此类中有一个方法Work是用来读取数据的!

@H_404_18@class@H_404_18@ ProgressBarWork
@H_404_18@ 3    @H_404_18@ Work()
@H_404_18@ 4 @H_404_18@     {
@H_404_18@ 5        @H_404_18@int iTotal = 50;@H_404_18@计算工作量
@H_404_18@ 6        @H_404_18@int iCount = 0@H_404_18@;
@H_404_18@ 7        @H_404_18@for (@H_404_18@int i = 0; i < iTotal; i++@H_404_18@)
@H_404_18@         {                 
@H_404_18@ 9              System.Threading.Thread.Sleep(6);@H_404_18@模拟工作                             iCount = i;
@H_404_18@           }
@H_404_18@11       } }

继续完善此方法,这个方法虽然完成了读取数据的任务,但是如何让外部的ProgressBar知道此方法执行的状态呢?

答案是:该方法从开始执行,中间每次读取,执行完毕要暴露出3个事件来,通知在这三种状态下,ProgressBar应该如何显示,为此我们要声明一个委托,三个事件!

??? 既然要用到事件,还需要用到自定义的EventArgs来传递状态,为此我们定义一个EventArgs

@H_404_18@ WorkEventArgs : EventArgs
@H_404_18@    {
@H_404_18@ 3         @H_404_18@主要是用来往外传递信息的
@H_404_18@ 4         @H_404_18@public@H_404_18@ WorkStage Stage;
@H_404_18@ 5         @H_404_18@string Info = ""@H_404_18@ 6         @H_404_18@int Position =  7         @H_404_18@public WorkEventArgs(WorkStage Stage,1)">string Info,1)">int@H_404_18@ Position)
@H_404_18@        {
@H_404_18@ 9             @H_404_18@this.Stage =@H_404_18@ Stage;
@H_404_18@10             @H_404_18@this.Info =@H_404_18@ Info;
@H_404_18@11             @H_404_18@this.Position =@H_404_18@ Position;
@H_404_18@12 @H_404_18@        }
@H_404_18@13 @H_404_18@    }
@H_404_18@14     @H_404_18@enum@H_404_18@ WorkStage
@H_404_18@15 @H_404_18@16         BeginWork,1)">准备工作
@H_404_18@17         DoWork,1)">正在工作  
@H_404_18@18         EndWork,1)">工作结束
@H_404_18@19     }

接着在ProgressBarWork类中定义事件

@H_404_18@void PBWorkEventHandler(start work模拟工作
@H_404_18@19                 iCount =@H_404_18@ i;
@H_404_18@20                 SendEvents(@H_404_18@new WorkEventArgs(WorkStage.DoWork,1)">working" +@H_404_18@ iCount.ToString(),iCount));
@H_404_18@21 @H_404_18@            }
@H_404_18@22             SendEvents(@H_404_18@new WorkEventArgs(WorkStage.EndWork,1)">end work23 @H_404_18@24 
@H_404_18@25         @H_404_18@ SendEvents(WorkEventArgs e)
@H_404_18@26 @H_404_18@27             @H_404_18@switch@H_404_18@ (e.Stage)
@H_404_18@28 @H_404_18@29                 @H_404_18@case@H_404_18@ WorkStage.BeginWork:
@H_404_18@30                     @H_404_18@if (OnStartWorkEvent != @H_404_18@null) OnStartWorkEvent(@H_404_18@this

拿"方法执行前"来说,我们需要在UI线程中做如下编码

@H_404_18@1 ProgressBarWork work = @H_404_18@ ProgressBarWork();
@H_404_18@2  @H_404_18@订阅事件
@H_404_18@3  work.OnStartWorkEvent += @H_404_18@ PBWorkEventHandler(WorkStart);
@H_404_18@4 @H_404_18@其他事件订阅...

然后调用work.Work()方法来开始读取数据,我们通过前面的学习可以得知,如果要做到ProgressBar的显示和数据处理同步,必须单独开一个线程来做数据处理

@H_404_18@1 System.Threading.ThreadStart startWork =@H_404_18@ work.Work;
@H_404_18@2 System.Threading.Thread thread = @H_404_18@ System.Threading.Thread(startWork);
@H_404_18@3 thread.Start();

这样在WorkStart方法中就可以设置ProgressBar中的初始值了

@H_404_18@1  @H_404_18@void WorkStart(5     }

如果按照单线程的思想,这样编码是没有问题的,但是如果运行这段程序,会抛出如下异常!

?

什么原因?这里的this.statusProgressBar是不会运行成功的,因为这个方法不是有UI线程来调用的,必须通过control.Invoke来给ProgressBar赋值!

@H_404_18@   {
@H_404_18@ 3       PBWorkEventHandler del =@H_404_18@ SetMaxValue;
@H_404_18@ 4       @H_404_18@this.BeginInvoke(del,1)">new @H_404_18@[] { sender,e });     
@H_404_18@ 5 @H_404_18@   }
@H_404_18@ 6  @H_404_18@void SetMaxValue(@H_404_18@ 8       @H_404_18@ 9       @H_404_18@10    }

?这样就确保了SetMaxValue方法是在UI线程中执行的

UI界面完整代码如下:

@H_404_18@ ImitateProgressBar()
@H_404_18@ 3             ProgressBarWork work = @H_404_18@ 4             @H_404_18@ 5             work.OnStartWorkEvent += @H_404_18@ 6             work.OnDoWorkEvent += @H_404_18@ PBWorkEventHandler(Working);
@H_404_18@ 7             work.OnEndWorkEvent += @H_404_18@ PBWorkEventHandler(WorkEnd);
@H_404_18@ 8             System.Threading.ThreadStart startWork =@H_404_18@ 9             System.Threading.Thread thread = @H_404_18@            thread.Start();
@H_404_18@     }
@H_404_18@12 
@H_404_18@13         @H_404_18@15             PBWorkEventHandler del =5           
@H_404_18@6      }

这个方法已经是在新开的线程上执行的,只要确保在新的线程上利用UI线程去给ProgressBar赋值即可

三、在这个例子中我们还可以看出Control.Invoke和Control.BeginInvoke这两个方法的重要功能:

是在多线程的环境下 确保用UI线程去执行一些调用控件的方法,因为其他线程无法访问UI控件!!!!,这是上篇文章所没有提到的!

(编辑:北几岛)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读