VB.NET 进度条后台工作者
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13206926/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
VB.NET progressbar backgroundworker
提问by tmighty
When my application starts, and it has just been upgraded, I am doing a local database update (sqlite).
当我的应用程序启动并且刚刚升级时,我正在执行本地数据库更新 (sqlite)。
It is like that: The user starts my app, and then I start the upgrade process. During this upgrade process I am showing a form that has a continuous progressbar. This form closes when the upgrade process is done and the user can then start using my application.
就像这样:用户启动我的应用程序,然后我开始升级过程。在此升级过程中,我显示了一个具有连续进度条的表单。升级过程完成后,此表单将关闭,然后用户可以开始使用我的应用程序。
But the progressbar won't animate since the upgrade process is so intensive.
但是进度条不会动画,因为升级过程非常密集。
In my old VB6 version I used an ActiveX-Exe that has 1 form and shows a progressbar. This was my "background worker".
在我的旧 VB6 版本中,我使用了一个 ActiveX-Exe,它有 1 个表单并显示一个进度条。这是我的“后台工作者”。
I am not sure if I can use the same approach in VB.NET.
我不确定是否可以在 VB.NET 中使用相同的方法。
I have only seen examples that then do the work in the background worker, but I have not seen any examples where the progressbar itself was the background worker.
我只看到了在后台工作人员中完成工作的示例,但我还没有看到任何进度条本身是后台工作人员的示例。
The database upgrade needs to be blocking, the user may NOT use my application before the database upgrade was done. This means that only the progressbar should "out of process", but not the upgrading.
数据库升级需要阻塞,用户在数据库升级完成之前不能使用我的应用程序。这意味着只有进度条应该“退出进程”,而不是升级。
Thank you very much!
非常感谢!
回答by Jeremy Thompson
First read this: Use of Application.DoEvents()
首先阅读这个:Application.DoEvents()的使用
So after reading the above answer you will never using DoEvents ever again, and without the DoEvents (and/or Invalidating the ProgressBar so its Paint event will fire) the "progressbar won't animate since the upgrade process is so intensive"
因此,在阅读上述答案后,您将永远不会再使用 DoEvents,并且如果没有 DoEvents(和/或使 ProgressBar 无效,因此它的 Paint 事件将触发)“进度条将不会动画,因为升级过程如此密集”
Hence Cthulhu's comment - "You can make a dialog with a progressbar, make that dialog modal and execute your db-stuff on a backgroundworker." is one of the best ways forward.
因此克苏鲁的评论 - “您可以创建一个带有进度条的对话框,使该对话框成为模态并在后台工作人员上执行您的 db-stuff。” 是最好的前进方式之一。
I have translated a C# implementation of this that I use, you should be able to drop it straight in.
我已经翻译了我使用的 C# 实现,您应该可以直接将其放入。
This is the ProgressBar Form:
这是 ProgressBar 表单:
Public Partial Class ThinkingProgressBar
Inherits Form
Private startTime As System.DateTime = DateTime.Now
Public Sub New()
InitializeComponent()
End Sub
Private Sub lblClose_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs)
Me.Tag = "Cancelled"
Me.Hide()
End Sub
Public Sub SetThinkingBar(ByVal switchedOn As Boolean)
If switchedOn Then
lblTime.Text = "0:00:00"
startTime = DateTime.Now
Timer1.Enabled = True
Timer1.Start()
Else
Timer1.Enabled = False
Timer1.Stop()
End If
End Sub
Private Sub timer1_Tick(sender As Object, e As EventArgs)
Dim diff As New TimeSpan()
diff = DateTime.Now.Subtract(startTime)
lblTime.Text = diff.Hours & ":" & diff.Minutes.ToString("00") & ":" & diff.Seconds.ToString("00")
lblTime.Invalidate()
End Sub
End Class
Drag/Drop a BackgroundWorker control onto the form, here are the background worker events:
将 BackgroundWorker 控件拖放到窗体上,这里是后台工作器事件:
Private Sub backgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
e.Result = e.Argument
'DirectCast(e.Result, ThinkingProgressBar).SetThinkingBar(True)
'DO LONG OPERATION HERE
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Dim dlg As ThinkingProgressBar = TryCast(e.Result, ThinkingProgressBar)
If IsNothing(dlg) = False Then
dlg.SetThinkingBar(False)
dlg.Close()
End If
End Sub
And here is the calling code for when your application starts and does the upgrading:
这是应用程序启动和升级时的调用代码:
Dim dlg As New ThinkingProgressBar()
dlg.SetThinkingBar(True)
BackgroundWorker1.RunWorkerAsync(dlg)
dlg.ShowDialog()
If IsNothing(dlg.Tag) = False AndAlso dlg.Tag.ToString() = "Cancelled" Then
Return
End If
A couple of things, you may prevent the user from Cancelling (ie lblClose_LinkClicked
) and put in protective/defensive programming to handle cases where the user kills the process or turns off their PC during the upgrade.
有几件事,您可能会阻止用户取消(即lblClose_LinkClicked
)并放入保护性/防御性编程来处理用户在升级过程中终止进程或关闭其 PC 的情况。
And the ProgressBar is actually an animated gif - and this will suit your usage because estimating the time it takes to update a database is very hard to predict:
ProgressBar 实际上是一个动画 gif - 这将适合您的使用,因为估计更新数据库所需的时间是非常难以预测的:
回答by NeverHopeless
From your requirements it seems to me that you are looking for:
根据您的要求,我认为您正在寻找:
Application.DoAction()
I have experienced in an application that there was a need to load 2000 to 3000 items related detail from xml and the implemented process was reading items one by one which hangs up the process. Using the above line in the loop resolved my issue. The UI did not hang-up and user was able to work on other forms. This appeared progressbar is now as background process
(upto some extent) to me.
我在一个应用程序中遇到过,需要从 xml 加载 2000 到 3000 个与项目相关的详细信息,并且实现的过程是一个一个地读取项目,从而挂断了进程。在循环中使用上面的行解决了我的问题。UI 没有挂断,用户可以在其他表单上工作。这progressbar is now as background process
在我看来(在某种程度上)。
Hope it helps!
希望能帮助到你!
回答by Adam Zuckerman
I understand your desire to make the progressbar the background thread, but I am fairly certain that you will not be able to do this. Because you want to update the visual components of your application, the UI needs to be the primary thread. It is easy enough to disable all of the controls on a form, including menu items.
我理解您想让进度条成为后台线程的愿望,但我相当肯定您将无法做到这一点。因为您要更新应用程序的可视组件,所以 UI 需要成为主线程。禁用表单上的所有控件非常容易,包括菜单项。
Let me suggest this process:
让我建议这个过程:
Show your form with the progressbar mentioned.
If you show any other forms, disable all child controls that are directly on the form. Depending on the control, you may have to walk through its child controls to disable them.
In the code that performs the database update, update the progressbar's value to what ever value you desire. Upon updating the value, call the progressbar's refresh method. This will force the progressbar to paint correctly.
Once your update completes, hide the progressbar, re-enable all of the controls on all of the forms that you disabled.
使用提到的进度条显示您的表单。
如果您显示任何其他窗体,请禁用直接位于窗体上的所有子控件。根据控件的不同,您可能需要遍历其子控件以禁用它们。
在执行数据库更新的代码中,将进度条的值更新为您想要的任何值。更新值后,调用进度条的刷新方法。这将强制进度条正确绘制。
更新完成后,隐藏进度条,重新启用您禁用的所有表单上的所有控件。
This will give you the appearance of a progressbar that is running in the background thread while still giving your application the blocking of the main thread as desired.
这将为您提供在后台线程中运行的进度条的外观,同时仍使您的应用程序根据需要阻塞主线程。
回答by WozzeC
This is not tested but I recall doing something like this to feed information to a BGW. Which would update the background worker contents.
这没有经过测试,但我记得做过这样的事情来向 BGW 提供信息。这将更新后台工作人员的内容。
First create a class(i.e. ProgExample) with the following variables and put it as a global object.
首先用下面的变量创建一个类(即ProgExample),并把它作为一个全局对象。
Dim ProgValue as Integer;
Dim ProgMax as Integer;
Then feed the class to the background worker.
然后将班级提供给后台工作人员。
BackgroundWorker1.RunWorkerAsync(_ProgExample)
Read it and hold it inside:
阅读它并把它放在里面:
Dim BGWProgExample as ProgExample = DirectCast(e.Argument, ProgExample),
In background worker do something the following:
在后台工作人员执行以下操作:
BGWProgressBar.Maximum = BGWProgExample.ProgMax
while BGWProgExample.ProgValue <> BGWProgExample.ProgMax
BGWProgressBar.Value = BGWProgExample.ProgValue
So when you've done something just update _ProgExample.ProgValue. Don't try to do this without a class by just passing ProgValue as argument. That would mean that you send a copy of ProgValue in its current state and it would not change if you were to update ProgValue. And if this doesn't do anything try the Application.DoEvents and/or Application.DoAction together with this.
因此,当您完成某些操作后,只需更新 _ProgExample.ProgValue。不要尝试通过将 ProgValue 作为参数传递来在没有类的情况下执行此操作。这意味着您发送当前状态的 ProgValue 副本,并且如果您要更新 ProgValue,它不会更改。如果这没有做任何事情,请尝试将 Application.DoEvents 和/或 Application.DoAction 与此一起使用。
回答by igrimpe
Maybe I dont understand the question, but isnt it really simple?
也许我不明白这个问题,但这不是很简单吗?
For i = ProgressBar1.Minimum To ProgressBar1.Maximum
ProgressBar1.Value = i
ProgressBar1.Update()
System.Threading.Thread.Sleep(25)
Next
The "Update" of Progressbar does the trick. Your code "blocks" (though I can not see, why it's desirable to have "application not respondig"), but the Progressbar gets updated.
Progressbar 的“更新”可以解决问题。您的代码“阻塞”(虽然我看不到,为什么需要“应用程序不响应”),但进度条会更新d。
BTW: For Windows Vista/7 (progressbar animation) you might check this: ProgressBar is slow in Windows Forms
顺便说一句:对于 Windows Vista/7(进度条动画),您可以检查一下:Windows Forms 中的 ProgressBar is slow
回答by Ric
You can raise an event in the background worker and then update the progress bar on the UI thread. You can raise events in your class and handle them in the form. When they are raised, you can call reportprogress() on the background worker.
您可以在后台工作程序中引发事件,然后更新 UI 线程上的进度条。您可以在类中引发事件并在表单中处理它们。当它们被提出时,您可以在后台工作人员上调用 reportprogress()。
some more info:
更多信息:
Performing long running UI changes without blocking the main thread