代码之家  ›  专栏  ›  技术社区  ›  Marcello

BackgroundWorker仅在取消时更新进度

  •  1
  • Marcello  · 技术社区  · 6 年前

    我想在表单上显示一个‘dinamic标签’,它只写‘loading’,而另一个线程正在工作。 标签应在此模式下更改:

    L、LO、LOA、LOAD、LOADI、LOADIN、LOADING、LOADING、LOAD、LOADI、LOADING、LOADING、LOADING

    我编写了代码,但只有当backgroundworker.cancellationpending=true时,才会调用“backgroundworker\u progresschanged”事件。

    在那一点上,所有的更新都会被发送。

    这里是密码

    Public Class Form1
    
      Dim WithEvents bgw As New BackgroundWorker
      Dim WithEvents I_MyClass As MyNewClass
      Dim lLoading As New Label
      Dim WithEvents T As New Timer
    
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        bgw.WorkerReportsProgress = True
        bgw.WorkerSupportsCancellation = True
        I_MyClass = New MyNewClass
        AddHandler I_MyClass.Start, AddressOf StartLoading
        AddHandler I_MyClass.Stop, AddressOf StopLoading
    
        With lLoading
            .Size = New Size(120, 25)
            .Location = New Point(10, 10)
        End With
        Me.Controls.Add(lLoading)
    
        T.Interval = 1000
        AddHandler T.Tick, AddressOf T_Tick
    
        T.Start()
      End Sub
    
      Private Sub T_Tick(sender As Object, e As EventArgs) Handles T.Tick
        T.Stop()
        I_MyClass.StartLoading()
      End Sub
    
      Public Sub StartLoading()
        If bgw.IsBusy Then Exit Sub
        bgw.RunWorkerAsync()
      End Sub
    
      Public Sub StopLoading()
        bgw.CancelAsync()
      End Sub
    
      Private Sub bgw_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
    
        Dim i As Integer = 1
        Dim loadingString As String = "Loading......."
        Do
            If (worker.CancellationPending = True) Then
                e.Cancel = True
                Exit Do
            Else
                Threading.Thread.Sleep(500)
                worker.ReportProgress(i)
                If i = loadingString.Count Then i = 1 Else i += 1
            End If
        Loop
      End Sub
    
      Private Sub bgw_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw.ProgressChanged
        Dim loadingString As String = "Loading......."
        Dim i As Integer = e.ProgressPercentage
        Dim l As Integer = lLoading.Text.Count
        If l < i Then
            lLoading.Text = loadingString.Substring(0, i)
        Else
            lLoading.Text = loadingString.Substring(i, l - i)
        End If
      End Sub
    
    End Class
    
    Public Class MyNewClass
      Sub New()
    
      End Sub
      Public Event Start()
      Public Event [Stop]()
    
      Public Sub StartLoading()
        RaiseEvent Start()
        ' simulate download
        For a = 0 To 10
            Threading.Thread.Sleep(1000)
        Next a
        RaiseEvent Stop()
      End Sub
    End Class
    

    不明白为什么“backgroundworker\u progresschanged”事件不称为报告部分进度,但只有当backgroundworker.cancellationpending=true时才会多次调用它。

    另外,我们也欢迎您的帮助。

    2 回复  |  直到 6 年前
        1
  •  2
  •   bommelding    6 年前

    不明白为什么“backgroundworker”progresschanged事件不称为报告部分进度

    因为你有一个计时器来启动非常阻塞,非常不异步的加载方法。

    似乎是从主线程调用此代码:

        For a = 0 to 10
            Threading.Thread.Sleep(1000)
        Next a
    

    所以你的应用程序会在11秒内完全失聪和哑巴。没有时间进行屏幕更新或进度事件,我们正忙于睡眠。

        2
  •  1
  •   Marcello    6 年前

    多亏了bommelding,我注意到我忘记在单独的线程中启动下载,所以bommelding让我注意到,指令'threading.thread.sleep()正在停止标签更新 这里的代码是正确的。

    Imports System.ComponentModel
    
    Public Class Form1
    
      Dim WithEvents bgw As New BackgroundWorker
      Dim WithEvents I_MyClass As MyNewClass
      Dim lLoading As New Label
      Dim WithEvents T As New Timer
    
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        bgw.WorkerReportsProgress = True
        bgw.WorkerSupportsCancellation = True
        I_MyClass = New MyNewClass
        AddHandler I_MyClass.Start, AddressOf StartLoading
        AddHandler I_MyClass.Stop, AddressOf StopLoading
    
        With lLoading
            .Size = New Size(120, 25)
            .Location = New Point(10, 10)
            .TextAlign = ContentAlignment.MiddleCenter
            .Tag = "Loading"
            For a = 0 To CStr(.Tag).Count - 1
                .Text += " "
            Next
        End With
        Me.Controls.Add(lLoading)
    
        T.Interval = 1000
        AddHandler T.Tick, AddressOf T_Tick
    
        T.Start()
      End Sub
    
      Private Sub T_Tick(sender As Object, e As EventArgs) Handles T.Tick
        T.Stop()
        I_MyClass.StartLoading()
      End Sub
    
      Public Sub StartLoading()
        If bgw.IsBusy Then Exit Sub
        bgw.RunWorkerAsync(CStr(lLoading.Tag).Count - 1)
      End Sub
    
      Public Sub StopLoading()
        bgw.CancelAsync()
      End Sub
    
      Private Sub bgw_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
        Dim limit As Integer = CInt(e.Argument)
        Dim i As Integer = 0
        Do
            If (worker.CancellationPending = True) Then
                e.Cancel = True
                Exit Do
            Else
                Threading.Thread.Sleep(100)
                worker.ReportProgress(i)
                If i = limit Then i = 0 Else i += 1
            End If
        Loop
        i = Nothing
        limit = Nothing
        worker = Nothing
      End Sub
    
      Private Sub bgw_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgw.ProgressChanged
        Dim loadingString As String = CStr(lLoading.Tag)
    
        Dim i As Integer = e.ProgressPercentage
        'Dim l As Integer = lLoading.Text.Count
        If lLoading.Text(i) <> loadingString(i) Then
            Mid(lLoading.Text, i + 1, 1) = loadingString(i)
        Else
            Mid(lLoading.Text, i + 1, 1) = " "
        End If
        i = Nothing
        loadingString = Nothing
      End Sub
    
      Private Sub bgw_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
        For a = 0 To CStr(lLoading.Tag).Count - 1
            lLoading.Text += " "
        Next
      End Sub
    End Class
    
    Public Class MyNewClass
      Sub New()
        bgwDoSameWork.WorkerReportsProgress = True
        bgwDoSameWork.WorkerSupportsCancellation = True
      End Sub
      Public Event Start()
      Public Event [Stop]()
      Private WithEvents bgwDoSameWork As New BackgroundWorker
    
    
      Public Sub StartLoading()
        ' simulate download
        If bgwDoSameWork.IsBusy = False Then
            RaiseEvent Start()
            bgwDoSameWork.RunWorkerAsync()
        End If
    
      End Sub
    
      Private Sub bgwDoSameWork_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgwDoSameWork.DoWork
        For a = 0 To 10
            Threading.Thread.Sleep(1000)
        Next a
      End Sub
    
      Private Sub bgwDoSameWork_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgwDoSameWork.RunWorkerCompleted
        RaiseEvent Stop()
      End Sub
    End Class