Обновление backgroundWorker только при отмене - PullRequest
0 голосов
/ 12 июня 2018

Я хочу показать в форме «динамическую метку», в которой просто пишется «Загрузка», пока работает другой поток.В этом режиме метка должна измениться:

L, Lo, Loa, Load, Loadi, Loadin, Загрузка, oading, ading, ding, ing, ng, g

Я написал код, нособытие 'BackGroundWorker_ProgressChanged, которое вызывается только тогда, когда BackGroundWorker.CancellationPending = True.

И в этот момент отправляются все обновления.

Здесь код

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_ProgressChanged не называется сообщением о частичном ходе, но вызывается несколько раз, только когда BackGroundWorker.CancellationPending = True.

PS Также приветствуется помощь на c #.

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Благодаря Bommelding я заметил, что забыл начать загрузку в отдельном потоке, так что Bommelding позволил мне заметить, что инструкция threading.thread.sleep () остановила обновление Label. Здесь код исправлен.

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
0 голосов
/ 12 июня 2018

Не понимаю, почему событие BackGroundWorker_ProgressChanged не называется сообщением о частичном ходе

Поскольку у вас есть таймер, который запускает очень блокирующий, очень не асинхронный метод StartLoading.

Похоже, вы вызываете этот код из основного потока:

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

, поэтому ваше приложение будет полностью глухим и немым в течение 11 секунд.Нет времени на обновления экрана или события прогресса, мы заняты сном.

...