VB.NET progressbar backgroundworker

时间:2012-11-03 07:11:26

标签: vb.net progress-bar backgroundworker

当我的应用程序启动时,它刚刚升级,我正在进行本地数据库更新(sqlite)。

就是这样: 用户启动我的应用程序,然后我开始升级过程。 在此升级过程中,我将显示一个具有连续进度条的表单。 升级过程完成后,此表单将关闭,然后用户可以开始使用我的应用程序。

但由于升级过程非常密集,因此进度条不会生成动画。

在我的旧版VB6中,我使用了一个ActiveX-Exe,它有一个表单并显示一个进度条。这是我的“背景工作者”。

我不确定我是否可以在VB.NET中使用相同的方法。

我之前只看过后台工作者的工作,但我没有看到任何示例,其中progressbar本身就是后台工作者。

数据库升级需要阻止,用户可能在数据库升级完成之前不使用我的应用程序。这意味着只有进度条应该“进行中”,而不是升级。

非常感谢!

6 个答案:

答案 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 - 这将适合您的使用,因为估计更新数据库所需的时间很难预测:

enter image description here

答案 1 :(得分:3)

根据您的要求,我认为您正在寻找:

Application.DoAction()

我在应用程序中遇到过需要从xml加载2000到3000项相关细节的问题,并且已实现的进程逐个读取项目,这会挂起进程。在循环中使用上面的行解决了我的问题。用户界面没有挂起,用户可以在其他表单上工作。这对我来说是progressbar is now as background process(在某种程度上)。

希望它有所帮助!

答案 2 :(得分:3)

我理解你希望将进度条作为后台线程,但我相当肯定你将无法做到这一点。因为您想要更新应用程序的可视组件,所以UI必须是主要线程。很容易禁用表单上的所有控件,包括菜单项。

让我建议这个过程:

  1. 使用提到的进度条显示您的表单。

  2. 如果您显示任何其他表单,请禁用表单上直接显示的所有子控件。根据控件的不同,您可能需要遍历其子控件才能禁用它们。

  3. 在执行数据库更新的代码中,将进度条的值更新为您想要的值。更新值后,调用progressbar的refresh方法。这将强制进度条正确绘制。

  4. 更新完成后,隐藏进度条,重新启用您禁用的所有表单上的所有控件。

  5. 这将为您提供在后台线程中运行的进度条的外观,同时仍然根据需要为应用程序阻止主线程。

答案 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