9

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

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

但是进度条不会动画,因为升级过程非常密集。

在我的旧 VB6 版本中,我使用了一个具有 1 个表单并显示进度条的 ActiveX-Exe。这是我的“后台工作人员”。

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

我只看到了在后台工作人员中完成工作的示例,但我还没有看到进度条本身就是后台工作人员的任何示例。

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

非常感谢你!

4

6 回答 6

12

首先阅读此内容:Application.DoEvents() 的使用

因此,在阅读上述答案后,您将永远不会再使用 DoEvents,并且没有 DoEvents(和/或使 ProgressBar 无效,因此其 Paint 事件将触发)“progressbar 不会动画,因为升级过程非常密集”

因此 Cthulhu 的评论 - “您可以使用进度条创建对话框,使该对话框成为模态并在后台工作人员上执行您的 db-stuff。” 是最好的前进方式之一。

我已经翻译了我使用的 C# 实现,你应该可以直接把它放进去。

这是进度条表单:

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

在此处输入图像描述

于 2012-11-21T05:05:22.130 回答
3

根据您的要求,在我看来您正在寻找:

Application.DoAction()

我在一个应用程序中体验过,需要从 xml 加载 2000 到 3000 个项目相关的详细信息,并且实现的过程是一个一个地读取项目,这会挂起该过程。在循环中使用上述行解决了我的问题。UI 没有挂断,用户可以在其他表单上工作。这progressbar is now as background process在我看来(在某种程度上)。

希望能帮助到你!

于 2012-11-15T07:06:57.790 回答
3

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

让我建议这个过程:

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

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

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

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

这将为您提供在后台线程中运行的进度条的外观,同时仍为您的应用程序提供所需的主线程阻塞。

于 2012-11-20T00:06:13.767 回答
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 与此一起使用。

于 2012-11-15T07:43:50.093 回答
1

也许我不明白这个问题,但它真的很简单吗?

For i = ProgressBar1.Minimum To ProgressBar1.Maximum
        ProgressBar1.Value = i
        ProgressBar1.Update()
        System.Threading.Thread.Sleep(25)
    Next

Progressbar 的“更新”可以解决问题。您的代码“阻塞”(虽然我看不到,为什么需要“应用程序不响应”),但 Progressbar 得到更新d。

顺便说一句:对于 Windows Vista/7(进度条动画),您可以检查:ProgressBar is slow in Windows Forms

于 2012-11-15T10:31:26.117 回答
-1

您可以在后台工作人员中引发事件,然后在 UI 线程上更新进度条。您可以在班级中引发事件并以表格形式处理它们。当它们被提出时,您可以在后台工作人员上调用 reportprogress()。

更多信息:

在不阻塞主线程的情况下执行长时间运行的 UI 更改

于 2012-11-03T10:26:14.270 回答