none
Process_OutputDataReceived與 BackgroundWorker_ProgressChanged 如何連接使用 RRS feed

  • 一般討論

  • 環境:VS2008 VB.NET WindowsApplication

    我要執行一個長時間工作所以我放了一個BackgroundWorker來做背景處理及前端進度回報

    現在這個長時間工作中的一個步驟,需要執行cmd命令去執行一個EXE檔,這個EXE檔會輸出它的處理進度,

    我參考呼叫命令列程式並即時接收輸出這篇文章,

    使用Process_OutputDataReceived來取得cmd輸出的進度,

    但在Process_OutputDataReceived 如何取得BackgroundWorker物件去進行進度回報及程序中斷呢?

      Private Function ExecuteBackgroundTask(ByVal objBgw As BackgroundWorker, ByVal objArgs As DoWorkEventArgs) As Boolean
            If Step1(objBgw, objArgs) = False Then Return False '如果子程式有中斷回傳False,於此再回傳False結束背景程式執行
            If Step2Cmd(objBgw, objArgs) = False Then Return False
            '執行其他步驟
            If Step10(objBgw, objArgs) = False Then Return False
            Return True
        End Function
    
        Private Function Step1(ByVal objBgw As BackgroundWorker, ByVal objArgs As DoWorkEventArgs) As Boolean
            Dim i As Integer
            For i = 0 To 10000
                '執行命令
                If UpdateProgress(i, "Step1_" & i, objBgw, objArgs) = False Then Return False '[檢查進度及狀態]如果進度程式有中斷回傳False,於此再回傳False通知背景程式進行結束
            Next
            Return True
        End Function
    
        Private Function Step2Cmd(ByVal objBgw As BackgroundWorker, ByVal objArgs As DoWorkEventArgs) As Boolean
            Dim objProcess As Process = New Process()
            objProcess.StartInfo.FileName = "這裡放cmd命令"
            objProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
            objProcess.StartInfo.RedirectStandardInput = True
            objProcess.StartInfo.RedirectStandardOutput = True
            objProcess.StartInfo.CreateNoWindow = True
            objProcess.StartInfo.UseShellExecute = False
            AddHandler objProcess.OutputDataReceived, AddressOf Process_OutputDataReceived
            If objProcess.Start() Then
                objProcess.BeginOutputReadLine()
                objProcess.WaitForExit()
            End If
            Return True
        End Function
    
    
        Public Sub Process_OutputDataReceived(ByVal sender As System.Object, ByVal e As System.Diagnostics.DataReceivedEventArgs)
            If e.Data IsNot Nothing Then
                If UpdateProgress(Integer.Parse(e.Data), "Step1_2", objBgw, objArgs) = False Then Return False '如何傳入BackgroundWorker及DoWorkEventArgs物件及如何回傳是否中斷通知背景程式進行結束
            End If
        End Sub
    
        '需傳入BackgroundWorker及DoWorkEventArgs物件以供程式變更狀態
        '需傳出Boolean供主程序判斷使用者已中斷提前進行程式結束
        Private Function UpdateProgress(ByVal intValue As Integer, ByVal strMessage As String, ByVal objBgw As BackgroundWorker, ByVal objArgs As DoWorkEventArgs) As Boolean
            If objBgw.CancellationPending = True Then '檢查是否中斷執行
                objArgs.Cancel = True '設定參數中斷執行
                Return False
            Else
                objBgw.ReportProgress(intValue, strMessage) '設定進度數值及訊息
                Return True
            End If
        End Function

    2015年8月19日 上午 03:58

所有回覆

  • 我是不太懂你要BackgroundWorker要做什麼,不過簡單一點就是設成全域變數

    或是把Process_OutputDataReceived用lambda的方式寫在Step2Cmd裡面,這樣可以直接存取BackgroundWorker

    2015年8月19日 上午 04:46
  • 2015年8月19日 上午 08:37
  • 我是不太懂你要BackgroundWorker要做什麼,不過簡單一點就是設成全域變數

    或是把Process_OutputDataReceived用lambda的方式寫在Step2Cmd裡面,這樣可以直接存取BackgroundWorker

    BackgroundWorker用來執行長時間工作,回傳進度或進行中斷,可避免畫面被鎖住.

    VS2008 VB.NET 對 lambda 的支持度不高,不能執行多行的程序,所以不能用.

    我將BackgroundWorker設成全域變數,可以在UpdateProgress中取得它,
    但我要中斷程序時,怎麼回傳ExecuteBackgroundTask中斷執行呢?
    下面程式在Step2Cmd中斷後,Step3仍會被執行,可看到會建立文字檔!
    要怎麼樣才能在Step2Cmd中斷後,ExecuteBackgroundTask也終止執行
    ,也就是不會再執行後續步驟Step3

    Imports System.IO
    Imports System.Text.RegularExpressions
    Imports System.ComponentModel
    Public Class Form4
        Private objBgw As BackgroundWorker
        Private objArgs As DoWorkEventArgs
        Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        End Sub
    
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecute.Click
            '背景工作
            bgwTask.RunWorkerAsync()
        End Sub
    
        ''' <summary>
        ''' [中斷]按鈕點擊事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub btnInterrupt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInterrupt.Click
            If MessageBox.Show("是否中斷執行?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) = DialogResult.Yes Then
                objBgw.CancelAsync()
                tssProgress.Value = 0
                tssMessage.Text = "正在中斷程序中,請稍等…"
            End If
        End Sub
    
        ''' <summary>
        ''' [主表單]關閉事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks>若建立書籍程序正在執行,則無法關閉視窗</remarks>
        Private Sub FormMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            If objBgw.IsBusy = True Then
                MessageBox.Show("程序正在執行中無法關閉視窗!" & vbCrLf & "若要中止程序請按[中斷]按鈕。")
                e.Cancel = True
            End If
        End Sub
    
        ''' <summary>
        ''' [背景工作]作業開始事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwTask.DoWork
            objBgw = sender
            objArgs = e
            ExecuteBackgroundTask()
        End Sub
    
        ''' <summary>
        ''' [背景工作]進度變更事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwTask.ProgressChanged
            tssProgress.Value = e.ProgressPercentage
            tssMessage.Text = e.UserState
        End Sub
    
        ''' <summary>
        ''' [背景工作]作業完成事件
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgwTask.RunWorkerCompleted
            If e.Cancelled = True Then
                '顯示提示訊息
                MessageBox.Show("執行已中斷!")
            ElseIf e.Error IsNot Nothing Then
                '顯示提示訊息
                MessageBox.Show(e.Error.Message)
            Else
                '顯示提示訊息
                MessageBox.Show("電子書已製作完成。")
            End If
        End Sub
    
        Private Function ExecuteBackgroundTask() As Boolean
            If Step1() = False Then Return False '如果子程式有中斷回傳False,於此再回傳False結束背景程式執行
            If Step2Cmd() = False Then Return False '在這裡中斷
            If Step3() = False Then Return False '這裡仍會執行
    
    
            Return True
        End Function
        Public Function Step1() As Boolean
            Dim i As Integer
            For i = 0 To 10
                If UpdateProgress("Step1進度", i) = False Then Return False
                System.Threading.Thread.Sleep(1000)
            Next
            Return True
        End Function
        Public Function Step3() As Boolean
            Dim i As Integer
            File.CreateText("C:\Users\MAY\Desktop\test.txt") '測試Step3是否有被執行
            For i = 0 To 10
                If UpdateProgress("Step3進度", i) = False Then Return False
                System.Threading.Thread.Sleep(1000)
            Next
            Return True
        End Function
    
    
        Public Function Step2Cmd()
            Dim objProcess As Process
            objProcess = New Process 
            objProcess.StartInfo.FileName ="命令內容"
            objProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
            objProcess.StartInfo.RedirectStandardInput = True
            objProcess.StartInfo.RedirectStandardOutput = True
            objProcess.StartInfo.CreateNoWindow = True
            objProcess.StartInfo.UseShellExecute = False
            AddHandler objProcess.OutputDataReceived, AddressOf objProcess_OutputDataReceived
    
            Try
                If objProcess.Start() Then
                    objProcess.BeginOutputReadLine()
                    objProcess.WaitForExit()
                End If
            Catch ex As Exception
    
            Finally
                objProcess.Close()
            End Try
            Return True
        End Function
    
        Public Sub objProcess_OutputDataReceived(ByVal sender As System.Object, ByVal e As System.Diagnostics.DataReceivedEventArgs)
            Dim objMatch As Match
            If e.Data IsNot Nothing Then
                objMatch = Regex.Match(e.Data, "^NOTICE  processing PDF page (\d+)")
                If objMatch.Success Then
                    '更新進度
                    If UpdateProgress("CMD進度", Integer.Parse(objMatch.Groups(1).Value)) = False Then
                        Dim objProcess As Process = CType(sender, Process)
                        If objProcess.HasExited = False Then
                            objProcess.Kill()
                            '如何停止ExecuteBackgroundTask的執行
                        End If
                    End If
                    'Return False
    
                End If
            End If
    
    
        End Sub
    
    
        Private Function UpdateProgress(ByVal strMessage As String, ByVal intValue As Integer) As Boolean
            If objBgw.CancellationPending = True Then '檢查是否中斷執行
                objArgs.Cancel = True '設定參數中斷執行
                Return False
            Else
                strMessage = strMessage & ":" & intValue
                objBgw.ReportProgress(intValue, strMessage) '設定進度數值及訊息
                Return True
            End If
        End Function

    2015年8月20日 上午 06:12
  • 看看這篇討論有沒有幫助:Add progressBar to view progress percentage to a process in c#

    它似乎只在說cmd取得進度可以用OutputDataReceived,
    這個我有參考呼叫命令列程式並即時接收輸出這篇文章,
    我要問的是OutputDataReceived如何和BackgroundWorker的物件做連接處理?

    2015年8月20日 上午 06:36
  • 我想應該宣告一個全域變數去記,objProcess.Kil()的時候去把變數標記成false

    然後step3是認這個變數來決定要不要執行

    2015年8月20日 上午 06:41
  • 不過user會連發按按鈕的話,你得多考慮該變數的資源爭搶
    2015年8月20日 上午 06:42
  • 另外再宣告一個全域變數,我覺得不太合適,

    因為我目前的判斷是用function 的return 值來判斷是否離開

    在Step2這改用另一個全域變數來判斷,和其他處的判斷就不同了

    我目前想用Process.ExitCode來判斷試看看,

    只是我的cmd命令是Swftools的pdf2swf,

    它的ExitCode我不確定,不知那裡可以查到它的ExitCode列表,

    目前只能中斷再去取他的ExitCode值,只要為這個值就return false結束背景程序,

    不知有其他方法可以解決這個問題嗎?

                    objProcess.WaitForExit()
                    If objProcess.ExitCode = -1 Then
                        Return False
                    End If

    2015年8月20日 上午 08:47