VB.Net Асинхронный фоновый работник внутри цикла - PullRequest
0 голосов
/ 08 июля 2010

Я использую Vb.net Visual Studio 2008. У меня есть процесс (system.diagnostics.process) для запуска в фоновом режиме, и он обновляет строку прогресса потока UI и метку, и я обработал его с помощью backgroundworker.runworkerAsync. Теперь проблема в том, что я должен работать один и тот же процесс некоторое время с разными входами.

Кодовый блок:

Private Sub fnStartEvent(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.click

Dim inputFolder = Directory.GetFiles(textboxSourceFolder.text) 
Dim currentNumberOfFile As Integer=1
For each Files in inputFolder
   Dim arguments As Object = Files
   updateProgressStatus(0, currentNumberOfFile)
   BackgroundWorker1.WorkerReportsProgress = True
   BackgroundWorker1.RunWorkerAsync(New Object() {arguments})
  currentNumberOfFile += 1
  Next       
End Sub

  Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
  'uses the arguments
      Dim Bg_process As System.Diagnostics.Process = New System.Diagnostics.Process
            With Bg_process.StartInfo
                .Arguments = str_arguments
                .FileName = ffmpegPath
                .CreateNoWindow = True
                .UseShellExecute = False
                .RedirectStandardOutput = True
                .RedirectStandardError = True
            End With

            Bg_process.Start()
            Dim outputReader As StreamReader = Bg_process.StandardError
            Dim output As String

            While Not Bg_process.HasExited
                output = outputReader.ReadLine()
                BackgroundWorker1.ReportProgress(0, output)
                Threading.Thread.Sleep(500)
            End While
      End Sub

 Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
   ' process args

updateProgressStatus(args(0), args(1) )
End Sub

Private Function BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)  Handles BackgroundWorker1.RunWorkerCompleted
            Messagebox.Show(e.error.ToString)
End Try

  Sub updateProgressStatus(ByVal progressValue As Integer, ByVal progressStatus As String)
progressBar.value = progressValue
lblprogressStatus.Text = progressStatus
      End Sub

Проблема здесь в том, что метод fnStartEvent после запуска вызывает метод BackgroundWorker1.runWorkerAsync, который выполняется в отдельном потоке и не ожидает завершения потока, а затем переходит к следующей строке кода, то есть возвращается к следующий элемент, и он возвращается к той же строке BackgroundWorker1.runWorkerAsync и выдает исключение, что он уже выполняется.

Пробовал 1.

    Private Sub fnStartEvent(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.click
    Dim inputFolder = Directory.GetFiles(textboxSourceFolder.text) 
    Dim currentNumberOfFile As Integer=1
    For each Files in inputFolder

       Dim arguments As Object = Files
       updateProgressStatus(0, currentNumberOfFile)
       BackgroundWorker1.WorkerReportsProgress = True
       BackgroundWorker1.RunWorkerAsync(New Object() {arguments})
    ''
       Do Until BackgroundWorker1.IsBusy
       Thread.Sleep(500)
       Loop

  currentNumberOfFile += 1
  Next       
End Sub

Но это не обновляет поток пользовательского интерфейса, используемый для обозначения прогресса.

2. Поместите весь процесс в поток DoWork и выполните цикл для каждого файла там, но это возвращает кросс-поточную ошибку при обновлении индикатора выполнения.

какова стандартная процедура выполнения цикла для фонового работника, ожидающего завершения, а также обновления пользовательского интерфейса без его блокировки.

1 Ответ

0 голосов
/ 08 июля 2010

Всякий раз, когда вы используете Thread.Sleep, вы на самом деле спите текущий поток, который подключен к вашему классу запуска (т. Е. Form). Поэтому, если вы спите в своем основном потоке, обновления пользовательского интерфейса не произойдут.

Согласно статье MSDN, касающейся BackgroundWorker.IsBusy , вам необходимо создать Application.DoEvents. Код ниже скопирован из статьи, указанной выше.


Private Sub downloadButton_Click( _
    ByVal sender As Object, _
    ByVal e As EventArgs) _
    Handles downloadButton.Click

    ' Start the download operation in the background.
    Me.backgroundWorker1.RunWorkerAsync()

    ' Disable the button for the duration of the download.
    Me.downloadButton.Enabled = False

    ' Once you have started the background thread you 
    ' can exit the handler and the application will 
    ' wait until the RunWorkerCompleted event is raised.

    ' If you want to do something else in the main thread,
    ' such as update a progress bar, you can do so in a loop 
    ' while checking IsBusy to see if the background task is
    ' still running.
    While Me.backgroundWorker1.IsBusy
        progressBar1.Increment(1)
        ' Keep UI messages moving, so the form remains 
        ' responsive during the asynchronous operation.
        Application.DoEvents()
    End While
End Sub
...