VB.Net 循环内的异步后台工作者

发布于 2024-09-08 07:42:50 字数 3232 浏览 2 评论 0原文

我使用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

但这不会更新用于表示进度的 Ui 线程。

2.将整个过程放入DoWork线程中,并为其中的每个文件循环,但这会在进度条更新中返回跨线程错误。

执行后台工作循环等待完成以及更新 UI 而不阻塞它的标准程序是什么。

Im using Vb.net visual studio 2008. i have got a process(system.diagnostics.process) to be run in background and it updates the Ui thread progressbar and a label and i have worked it using backgroundworker.runworkerAsync. Now the problem is i have to work the same process for a number of time with different inputs.

The code block is :

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

The problem in here is the fnStartEvent method once gets started, it calls BackgroundWorker1.runWorkerAsync process and that runs in a seperate thread and does not wait for the thread to complete and it moves to the next line of code i.e loops to the next item and it returns to same BackgroundWorker1.runWorkerAsync line and throws exception that it is already running.

Tried
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

But this does not updates the Ui thread used to denote progress.

2.Put the whole process inside the DoWork thread and loop for each file in there itself, but that to returns the cross thread error in progress bar updation.

what is the standard procedure in executing a loop for the backgroundworker to wait for finishing as well as update the UI without blocking it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

掩饰不了的爱 2024-09-15 07:42:50

每当您使用 Thread.Sleep 时,您实际上都在休眠挂接到启动类(即 Form)的当前线程。因此,如果您休眠主线程,则不会发生 UI 更新。

根据有关 的 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

Whenever you use Thread.Sleep, you are actually sleeping the current thread that is hooked to your startup class (ie. Form). So, if you sleep your main thread, no UI updates will happen.

Per the MSDN article regarding BackgroundWorker.IsBusy, you need to throw an Application.DoEvents. Code below is copied from the article linked above.


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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文