VB.NET progressbar backgroundworker
当我的应用程序启动,并且刚刚升级时,我正在执行本地数据库更新(sqlite)。
这是这样的:用户启动我的应用程序,然后我开始升级过程。 在此升级过程中,我正在显示一个具有连续进度条的表单。 此表单在升级过程完成后closures,然后用户可以开始使用我的应用程序。
但是由于升级过程非常密集,进度条不会生成animation。
在我以前的VB6版本中,我使用了一个ActiveX-Exe,它有一个窗体并显示一个进度条。 这是我的“背景工作者”。
我不确定是否可以在VB.NET中使用相同的方法。
我只看到了后台工作人员的例子,但是我还没有看到任何进度条本身就是后台工作的例子。
数据库升级需要被阻止,在数据库升级完成之前用户可能不能使用我的应用程序。 这意味着只有进度条应该“失控”,而不是升级。
非常感谢你!
首先阅读这个: 使用Application.DoEvents()
所以在阅读上面的答案之后,您将永远不会再使用DoEvent,并且没有DoEvents(和/或使ProgressBar无效,因此它的Paint事件将触发)“进度条不会animation,因为升级过程非常密集”
因此,克苏鲁的评论 – “你可以做一个进度条的对话框,使对话框模式和执行你的数据库的东西在背景工作。 是最好的方法之一。
我已经翻译了一个我使用的C#实现,你应该可以直接删除它。
这是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
将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
这里是您的应用程序启动时的调用代码,并进行升级:
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
有几件事情,你可以阻止用户取消(即lblClose_LinkClicked
),并进行防护/防御编程,以处理用户在升级期间杀死进程或closures他们的PC的情况。
ProgressBar实际上是一个animationgif – 这将适合您的使用,因为估计更新数据库所花费的时间是很难预测的:
从您的要求看来,你在寻找:
Application.DoAction()
我曾经在一个应用程序中经历过,需要从xml加载2000到3000项相关的细节,并且实现的过程是逐个读取项目,这会挂起过程。 在循环中使用上面的行解决了我的问题。 用户界面没有挂断,用户可以在其他窗体上工作。 这个progressbar is now as background process
(在某种程度上)给我的。
希望它有帮助!
我明白你希望将进度栏作为后台线程,但我相当肯定你不能这样做。 因为要更新应用程序的可视组件,所以UI需要成为主线程。 禁用窗体上的所有控件(包括菜单项)很容易。
让我build议这个过程:
-
用提到的进度条显示你的表单。
-
如果您显示任何其他表单,请禁用直接在表单上的所有子控件。 取决于控件,您可能必须遍历其子控件才能禁用它们。
-
在执行数据库更新的代码中,将进度条的值更新为您所期望的值。 更新该值后,调用进度条的刷新方法。 这将强制进度条正确绘制。
-
更新完成后,隐藏进度栏,重新启用您禁用的所有表单上的所有控件。
这会给你在后台线程中运行的进度条的外观,同时仍然给你的应用程序根据需要阻塞主线程。
这是没有testing,但我记得做这样的事情给BGW提供信息。 这将更新后台工作人员的内容。
首先用下面的variables创build一个类(即ProgExample),并把它作为一个全局对象。
Dim ProgValue as Integer; Dim ProgMax as Integer;
然后把这个类喂给后台工作者。
BackgroundWorker1.RunWorkerAsync(_ProgExample)
阅读并保持在里面:
Dim BGWProgExample as ProgExample = DirectCast(e.Argument, ProgExample),
在后台工作者做以下事情:
BGWProgressBar.Maximum = BGWProgExample.ProgMax while BGWProgExample.ProgValue <> BGWProgExample.ProgMax BGWProgressBar.Value = BGWProgExample.ProgValue
所以当你做了一些更新_ProgExample.ProgValue。 不要试图通过只传递ProgValue作为参数来做到这一点。 这意味着你发送一个ProgValue在当前状态的副本,如果你要更新ProgValue,它不会改变。 如果这没有做任何事情,请尝试Application.DoEvents和/或Application.DoAction一起。
也许我不明白这个问题,但不是很简单吗?
For i = ProgressBar1.Minimum To ProgressBar1.Maximum ProgressBar1.Value = i ProgressBar1.Update() System.Threading.Thread.Sleep(25) Next
“进度条”的“更新”是有用的。 你的代码“块”(虽然我看不出来,为什么有“应用程序不响应”),但进度栏得到更新 d。
顺便说一句:对于Windows Vista / 7(进度条animation),您可能会检查: ProgressBar在Windows窗体中速度较慢
您可以在后台工作者中引发事件,然后在UI线程上更新进度条。 你可以在课堂上举办活动,并在表格中处理。 当他们被提出时,你可以调用后台worker的reportprogress()。
一些更多信息:
在不阻塞主线程的情况下执行长时间运行的UI更改