【问题标题】:VB.NET progressbar backgroundworkerVB.NET 进度条后台工作者
【发布时间】:2014-11-25 14:24:23
【问题描述】:

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

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

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

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

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

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

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

非常感谢!

【问题讨论】:

  • 您可以创建一个带有进度条的对话框,使该对话框成为模态并在后台工作人员上执行您的 db-stuff。,
  • 这正是我不想做的。我想反过来做。升级代码很大,如果可以避免的话,我不想把它移到后台工作程序中(不是为了懒惰,而是为了可读性)。
  • 阅读代表。完全可以做到这一点。
  • 移动更新代码应该不是问题。如果封装得当,则只需在后台工作人员中运行 UpdateToDB() 函数即可,而不是单击按钮或 VB6 进度条。
  • 你有什么代码可以给我们看吗?

标签: vb.net progress-bar backgroundworker


【解决方案1】:

首先阅读此内容:Use of Application.DoEvents()

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

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

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

【讨论】:

  • 感谢所有cmets和建议。他们中没有一个人真正支持我的方法,但我有一些替代方案,这里的这个实际上是写得最好的一个。非常感谢。
【解决方案2】:

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

Application.DoAction()

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

希望对你有帮助!

【讨论】:

    【解决方案3】:

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

    让我建议这个过程:

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

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

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

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

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

    【讨论】:

      【解决方案4】:

      这没有经过测试,但我记得做过类似的事情来向 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 与此一起使用。

      【讨论】:

        【解决方案5】:

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

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

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

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

        【讨论】:

          【解决方案6】:

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

          更多信息:

          Performing long running UI changes without blocking the main thread

          【讨论】:

          • 这假设我在后台工作人员中进行密集工作,不是吗?
          • 是的,它会假设 bg 任务很密集并且需要更改 UI。道歉!
          猜你喜欢
          • 2015-02-18
          • 1970-01-01
          • 1970-01-01
          • 2017-09-04
          • 1970-01-01
          • 2011-05-18
          • 1970-01-01
          • 2013-02-27
          • 2011-07-18
          相关资源
          最近更新 更多