完成另一个WPF/C#withBackgroundWorker后的两种方法在我的程序中,我有两个方法需要一段时间才能完成,每个方法大约需要几分钟.当方法执行时,我在一个单独的窗口中显示一个进度条,显示每个方法的进度。我的两个方法都在静态Utility类中。它们看起来像这样:publicstaticclassUtility{publicstaticboolTimeConsumingMethodOne(objectsender){for(inti=1;i<=100;i++){Thread.Sleep(100);(发件人作为BackgroundWorker).ReportProgress(i);}返回真;}publicstaticboolTimeConsumingMethodTwo(objectsender){for(inti=1;i<=100;i++){Thread.Sleep(50);(发件人作为BackgroundWorker).ReportProgress(i);}返回真;通过阅读SO中的类似问题,我了解到我应该使用BackgroundWorker并使用RunWorkerCompleted()来查看工作人员何时完成其工作。所以在我的Main()中,我使用了BackgroundWorer()并订阅了RunWorkerCompleted()方法。我的目标是首先运行TimeConsumingMethodOne()(并在运行时显示进度),然后一旦完成,运行TimeConsumingMethodTwo()并再次显示进度,并在完成时输出一个消息框(模拟我程序中的其他工作)。我的Main()如下所示:publicpartialclassMainWindow:Window{publicenumMethodType{One,Two}privateBackgroundWorkerworker=null;私有AutoResetEvent_resetEventOne=newAutoResetEvent(false);私有AutoResetEvent_resetEventTwo=newAutoResetEvent(false);私有ProgressBarWindowpbWindowOne=null;私有ProgressBarWindowpbWindowTwo=null;publicMainWindow(){InitializeComponent();}privatevoidbtnRun_Click(objectsender,RoutedEventArgse){RunMethodCallers(sender,MethodType.One);_resetEventOne.WaitOne();RunMethodCallers(发件人,MethodType.Two);_resetEventTwo.WaitOne();MessageBox.Show("完成!");}privatevoidRunMethodCallers(objectsender,MethodTypetype){worker=newBackgroundWorker();worker.WorkerReportsProgress=true;开关(类型){caseMethodType.One:worker.DoWork+=MethodOneCaller;worker.ProgressChanged+=worker_ProgressChangedOne;worker.RunWorkerCompleted+=worker_RunWorkerCompletedOne;布雷亚k;案例MethodType.Two:worker.DoWork+=MethodTwoCaller;worker.ProgressChanged+=worker_ProgressChangedTwo;worker.RunWorkerCompleted+=worker_RunWorkerCompletedTwo;休息;}worker.RunWorkerAsync();}privatevoidMethodOneCaller(objectsender,DoWorkEventArgse){Dispatcher.Invoke(()=>{pbWindowOne=newProgressBarWindow("运行方法一");pbWindowOne.Owner=this;pbWindowOne.Show();});Utility.TimeConsumingMethodOne(发件人);}privatevoidMethodTwoCaller(objectsender,DoWorkEventArgse){Dispatcher.Invoke(()=>{pbWindowTwo=newProgressBarWindow("运行方法二");pbWindowTwo.Owner=this;pbWindowTwo.Show();});Utility.TimeConsumingMethodTwo(发件人);}privatevoidworker_RunWorkerCompletedOne(objectsender,RunWorkerCompletedEventArgse){_resetEventOne.Set();}privatevoidworker_RunWorkerCompletedTwo(objectsender,RunWorkerCompletedEventArgse){_resetEventTwo.Set();}privatevoidworker_ProgressChangedOne(objectsender,ProgressChangedEventArgse){pbWindowOne.SetProgressUpdate(e.ProgressPercentage);}privatevoidworker_ProgressChangedTwo(objectsender,ProgressChangedEventArgse){pbWindowTwo.SetProgressUpdate(e.ProgressPercentage);我使用_resetEventOne.WaitOne();UI挂起如果我删除这两个等待,这两个方法将异步运行并且执行继续并在两个方法完成之前输出MessageBox。我究竟做错了什么?如何让程序完成我的第一个BackgroundWorker,然后转到下一个,然后在完成时输出MessageBox?现在我遇到的问题是当我使用_resetEventOne.WaitOne();用户界面挂起。如果我删除这两个等待,这两个方法将异步运行并且执行将继续并在两个方法完成之前输出MessageBox。我究竟做错了什么?当您调用WaitOne()时,您正在阻塞UI线程,导致UI挂起。如果你删除那个电话,那么你当然可以同时启动两个工作人员。有几种不同的方法可以解决您的问题。一种是与当前的实现紧密结合,只修复最小的最小值以使其工作。为此,您需要做的是在RunWorkerCompleted处理程序中执行实际的下一条语句,而不是使用事件等待处理程序执行。看起来像这样:publicpartialclassMainWindow:Window{publicenumMethodType{One,Two}privateBackgroundWorkerworker=null;私有ProgressBarWindowpbWindowOne=null;私有ProgressBarWindowpbWindowTwo=null;publicMainWindow(){InitializeComponent();}privatevoidbtnRun_Click(objectsender,RoutedEventArgse){RunMethodCallers(sender,MethodType.One);}privatevoidRunMethodCallers(objectsender,MethodTypetype){worker=newBackgroundWorker();worker.WorkerReportsProgress=true;开关(类型){caseMethodType.One:worker.DoWork+=MethodOneCaller;worker.ProgressChanged+=worker_ProgressChangedOne;worker.RunWorkerCompleted+=worker_RunWorkerCompletedOne;休息;案例MethodType.Two:worker.DoWork+=MethodTwoCaller;worker.ProgressChanged+=worker_ProgressChangedTwo;worker.RunWorkerCompleted+=worker_RunWorkerCompletedTwo;休息;}worker.RunWorkerAsync();}privatevoidMethodOneCaller(objectsender,DoWorkEventArgse){Dispatcher.Invoke(()=>{pbWindowOne=newProgressBarWindow("运行方法一");pbWindowOne.Owner=this;pbWindowOne.Show();});Utility.TimeConsumingMethodOne(发件人);}privatevoidMethodTwoCaller(objectsender,DoWorkEventArgse){Dispatcher.Invoke(()=>{pbWindowTwo=newProgressBarWindow("运行方法二");pbWindowTwo.Owner=this;pbWindowTwo.Show();});Utility.TimeConsumingMethodTwo(发件人);}privatevoidworker_RunWorkerCompletedOne(objectsender,RunWorkerCompletedEventArgse){RunMethodCallers(sender,MethodType.Two);}privatevoidworker_RunWorkerCompletedTwo(objectsender,RunWorkerCompletedEventArgse){MessageBox.Show("COMPLETED!");}privatevoidworker_ProgressChangedOne(objectsender,ProgressChangedEventArgse){pbWindowOne.SetProgressUpdate(e.ProgressPercentage);}privatevoidworker_ProgressChangedTwo(objectsender,ProgressChangedEventArgse){pbWindowTwo.SetProgressUpdate(e.ProgressPercentage);}也就是说,BackgroundWorker已被具有异步和等待的新的基于任务的API淘汰通过对代码进行一些小改动,它可以适应使用更新的习惯用法:publicpartialclassMainWindow:Window{publicenumMethodType{One,Two}privateProgressBarWindowpbWindowOne=null;私有ProgressBarWindowpbWindowTwo=null;publicMainWindow(){InitializeComponent();}privateasyncvoidbtnRun_Click(objectsender,RoutedEventArgse){awaitRunMethodCallers(sender,MethodType.One);等待RunMethodCallers(发件人,MethodType.Two);MessageBox.Show("完成!");}privateasyncTaskRunMethodCallers(objectsender,MethodTypetype){IProgressprogress;开关(类型){caseMethodType.One:progress=newProgress(i=>pbWindowOne.SetProgressUpdate(i));awaitTask.Run(()=>MethodOneCaller(progress));休息;案例MethodType.Two:progress=newProgress(i=>pbWindowTwo.SetProgressUpdate(i));awaitTask.Run(()=>MethodTwoCaller(progress));休息;}}privatevoidMethodOneCaller(IProgressprogress){Dispatcher.Invoke(()=>{pbWindowOne=newProgressBarWindow("Running方法一");pbWindowOne.Owner=this;pbWindowOne.Show();});Utility.TimeConsumingMethodOne(progress);}privatevoidMethodTwoCaller(IProgressprogress){Dispatcher.Invoke(()=>{pbWindowTwo=newProgressBarWindow("RunningMethodTwo");pbWindowTwo.Owner=this;pbWindowTwo.Show();});Utility.TimeConsumingMethodTwo(progress);}}为此,需要对Utility类进行小的调整:staticclassUtility{publicstaticboolTimeConsumingMethodOne(IProgressprogress){for(inti=1;iprogress){for(inti=1;i即Progress类替换了BackgroundWorker.ProgressChanged事件和ReportProgress()方法注意通过有了上面,代码变得更简单,更简单,并且以更直接的方式编写(即相关语句现在彼此在同一个方法中)。你给出的例子必须简化。那很好,但它确实意味着不知道Thread.Sleep()这个方法代表什么,其实很多时候,这种东西可以进一步重构,只异步完成长时间运行的工作。这有时可以进一步简化进度报告,因为它可以在等待每个异步执行的组件完成后完成工作。例如,假设循环中的工作本质上是异步的,或者是昂贵的,使用Task.Run()来执行每个循环迭代是合理的。出于同样的目的,可以使用Task.Delay():staticclassUtility{publicstaticasyncTaskTimeConsumingMethodOne(Actionprogress){for(inti=1;iTimeConsumingMethodTwo(Actionprogress){for(inti=1;i在上面,我也没有使用Progress。只是一个简单的Action委托,让调用者做任何他们想做的事情。通过此更改,您的窗口代码变得更加简单:publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();}privateasyncvoidbtnRun_Click(objectsender,RoutedEventArgse){awaitMethodOneCaller();等待MethodTwoCaller();MessageBox.Show("完成!");}privateasyncTaskMethodOneCaller(){ProgressBarWindowpbWindowOne=newProgressBarWindow("运行方法一"){Owner=this};pbWindowOne.Show();等待Utility.TimeConsumingMethodOne(i=>pbWindowOne.SetProgressUpdate(i));}privateasyncTaskMethodTwoCaller(){ProgressBarWindowpbWindowTwo=newProgressBarWindow("运行方法二"){Owner=this};pbWindowTwo.Show();等待Utility.TimeConsumingMethodTwo(i=>pbWindowTwo.SetProgressUpdate(i));}}当然,我借此机会去掉了MethodType枚举,直接调用方法,进一步缩短了代码。但即使您所做的只是避免使用Dispatcher.Invoke(),这仍然会大大简化您的代码。除此之外,如果您使用数据绑定来表示进度状态而不是直接设置值,WPF将隐式处理跨线程调用,因此如果您不能重构实用程序类代码。但是,与摆脱BackgroundWorker相比,这些改进微不足道。我建议这样做,但是您是否将时间投入到这些进一步的改进中并不重要。我更喜欢的一个选项是在不同的线程中使用这两种方法,并使用while循环来检查线程是否仍在运行,以及它是否使用Task.Delay()EG。以上就是C#学习教程:使用BackgroundWorker完成两种方法的全部内容,又一次WPF/C#分享。如果对大家有用,需要详细了解C#学习教程,希望大家多加关注—privateasyncvoidBlahBahBlahAsync(){ThreadtestThread=newThread(delegate(){});newThread=newThread(delegate(){Timeconsuming();});新线程.开始();while(testThread.IsAlive){awaitTask.Delay(50);}}privatevoidTimeconsuming(){//耗时的东西}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
