当我的应用程序启动时,它刚刚升级,我正在进行本地数据库更新(sqlite)。
就是这样: 用户启动我的应用程序,然后我开始升级过程。 在此升级过程中,我将显示一个具有连续进度条的表单。 升级过程完成后,此表单将关闭,然后用户可以开始使用我的应用程序。
但由于升级过程非常密集,因此进度条不会生成动画。
在我的旧版VB6中,我使用了一个ActiveX-Exe,它有一个表单并显示一个进度条。这是我的“背景工作者”。
我不确定我是否可以在VB.NET中使用相同的方法。
我之前只看过后台工作者的工作,但我没有看到任何示例,其中progressbar本身就是后台工作者。
数据库升级需要阻止,用户可能在数据库升级完成之前不使用我的应用程序。这意味着只有进度条应该“进行中”,而不是升级。
非常感谢!
答案 0 :(得分:12)
首先阅读:Use of Application.DoEvents()
因此,在阅读上述答案之后,您将永远不会再次使用DoEvents,并且没有DoEvents(和/或使ProgressBar无效,因此它的Paint事件将会触发)“升级过程如此密集,”进度条将不会生成动画“
因此,Cthulhu的评论 - “您可以使用进度条进行对话,使该对话框模态化并在后台工作者上执行您的数据库内容。”是最好的前进方式之一。
我已经翻译了我使用的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
)并进行保护/防御性编程,以处理用户在升级期间终止进程或关闭其PC的情况。
ProgressBar实际上是一个动画gif - 这将适合您的使用,因为估计更新数据库所需的时间很难预测:
答案 1 :(得分:3)
根据您的要求,我认为您正在寻找:
Application.DoAction()
我在应用程序中遇到过需要从xml加载2000到3000项相关细节的问题,并且已实现的进程逐个读取项目,这会挂起进程。在循环中使用上面的行解决了我的问题。用户界面没有挂起,用户可以在其他表单上工作。这对我来说是progressbar is now as background process
(在某种程度上)。
希望它有所帮助!
答案 2 :(得分:3)
我理解你希望将进度条作为后台线程,但我相当肯定你将无法做到这一点。因为您想要更新应用程序的可视组件,所以UI必须是主要线程。很容易禁用表单上的所有控件,包括菜单项。
让我建议这个过程:
使用提到的进度条显示您的表单。
如果您显示任何其他表单,请禁用表单上直接显示的所有子控件。根据控件的不同,您可能需要遍历其子控件才能禁用它们。
在执行数据库更新的代码中,将进度条的值更新为您想要的值。更新值后,调用progressbar的refresh方法。这将强制进度条正确绘制。
更新完成后,隐藏进度条,重新启用您禁用的所有表单上的所有控件。
这将为您提供在后台线程中运行的进度条的外观,同时仍然根据需要为应用程序阻止主线程。
答案 3 :(得分:1)
这未经过测试,但我记得做过这样的事情来向BGW提供信息。哪个会更新后台工作人员的内容。
首先使用以下变量创建一个类(即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与此一起使用。
答案 4 :(得分:1)
也许我不明白这个问题,但这不是很简单吗?
For i = ProgressBar1.Minimum To ProgressBar1.Maximum
ProgressBar1.Value = i
ProgressBar1.Update()
System.Threading.Thread.Sleep(25)
Next
Progressbar的“更新”可以解决问题。你的代码“阻塞”(虽然我看不出,为什么“应用程序没有响应”是可取的),但进度条得到更新 d。
BTW:对于Windows Vista / 7(进度条动画),您可以查看:ProgressBar is slow in Windows Forms
答案 5 :(得分:-1)
您可以在后台工作程序中引发事件,然后更新UI线程上的进度条。您可以在班级中提升事件并在表单中处理它们。当它们被引发时,你可以在后台worker上调用reportprogress()。
更多信息:
Performing long running UI changes without blocking the main thread