¿Hacer una pausa a un BackgrounWorker en VB.NET?

Iniciado por Crazy.sx, 17 Diciembre 2013, 21:34 PM

0 Miembros y 1 Visitante están viendo este tema.

Crazy.sx

Tengo una duda, estoy usando backgroundworker y ahora se me ocurre hacer una pausa al presionar un botón. No quiero cancelar la ejecución de este backgrounworker  sino todo lo contrario, pero la verdad es que no se cómo hacerlo.

Pesaba que este control podría existir algo como:

CitarBackgroundWorker1.state

:P   :¬¬

Espero que me puedan ayudar u orientarme mejor. Gracias.
Destruir K. LOL

Eleкtro

#1
Cita de: Loco.AR en 17 Diciembre 2013, 21:34 PMPesaba que este control podría existir algo como:

Personálmente por cosas como esta nunca me gustó el BackGroundWorker.

La forma correcta de pausar/reusmir un BackgroundWorker es usando un ManualResetEvent:

EDITO: Fíjate que debes especificar manuálmente los lugares en donde el procedimiento se puede pausar (_busy.WaitOne), y esto debes especificarlo sólamente en el eventhandler DoWork.

Imports System.ComponentModel

Public Class BackgroundWork

   Private _busy As New Threading.ManualResetEvent(True)

   Private WithEvents MyWorker As New BackgroundWorker

   Public Sub StartBackgroundTask()
       MsgBox("Starting the Thread...")
       MyWorker.WorkerSupportsCancellation = True
       MyWorker.WorkerReportsProgress = True
       MyWorker.RunWorkerAsync()
   End Sub

   Private Sub MyWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) _
   Handles MyWorker.DoWork

       For i = 1 To 5
           _busy.WaitOne(Threading.Timeout.Infinite)
           MyWorker.ReportProgress(MsgBox("Thread is working... " & CStr(i)))
       Next i

   End Sub

   Private Sub MyWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) _
   Handles MyWorker.RunWorkerCompleted

       MsgBox("Thread Done!")

   End Sub

   Public Sub PauseWorker()

       If MyWorker.IsBusy Then
           _busy.Reset()
           MsgBox("Thread Paused!")
       End If

   End Sub

   Public Sub ContinueWorker()
       _busy.[Set]()
       MsgBox("Thread Resumed!")
   End Sub

End Class


EDITO 2: Un ejemplo mejor elaborado:

Código (vbnet) [Seleccionar]
' BackgroundWorker Example
'
' // By Elektro H@cker

#Region " Usage Examples "

'Public Class Form1

'    Private MyWorker As New BackgroundWork

'    Private Shadows Sub Load() Handles MyBase.Load
'        MyWorker.StartBackgroundTask()
'    End Sub

'    Private Sub Button_Pause_Click() Handles Button_Pause.Click
'        MyWorker.Pause()
'    End Sub

'    Private Sub Button_Resume_Click() Handles Button_Resume.Click
'        MyWorker.Resume()
'    End Sub

'    Private Sub Button_Cancel_Click() Handles Button_Cancel.Click
'        MyWorker.Cancel()
'    End Sub

'End Class

#End Region

#Region " BackgroundWorker "

Public Class BackgroundWork

    ''' <summary>
    ''' The BackgroundWorker object.
    ''' </summary>
    Private WithEvents MyWorker As New System.ComponentModel.BackgroundWorker

    ''' <summary>
    ''' ManualResetEvent object to pause/resume the BackgroundWorker.
    ''' </summary>
    Private _busy As New Threading.ManualResetEvent(True)


    ''' <summary>
    ''' This will start the BackgroundWorker.
    ''' </summary>
    Public Sub StartBackgroundTask()

        MsgBox("Starting the Thread...")
        MyWorker.WorkerSupportsCancellation = True
        MyWorker.WorkerReportsProgress = True
        MyWorker.RunWorkerAsync()

    End Sub

    ''' <summary>
    ''' This is the work to do on background.
    ''' </summary>
    Private Sub MyWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) _
    Handles MyWorker.DoWork

        For i = 1 To 5

            If MyWorker.CancellationPending = True Then
                e.Cancel = True
                Exit For
            Else
                _busy.WaitOne(Threading.Timeout.Infinite) ' Indicate that here can be paused the Worker.
                MyWorker.ReportProgress(
                    MsgBox("Thread is working... " & i)
                    )
            End If

        Next i

    End Sub

    ''' <summary>
    ''' This happens when the BackgroundWorker is completed.
    ''' </summary>
    Private Sub MyWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
    Handles MyWorker.RunWorkerCompleted

        If e.Cancelled = True Then
            MsgBox("Thread cancelled")

        ElseIf e.Error IsNot Nothing Then
            MsgBox("Thread error")

        Else
            MsgBox("Thread Done!")

        End If

    End Sub

    ''' <summary>
    ''' This will pause the BackgroundWorker.
    ''' </summary>
    Public Sub Pause()

        If MyWorker.IsBusy Then
            _busy.Reset()
            MsgBox("Thread Paused!")
        End If

    End Sub

    ''' <summary>
    ''' This will resume the BackgroundWorker.
    ''' </summary>
    Public Sub [Resume]()
        _busy.[Set]()
        MsgBox("Thread Resumed!")
    End Sub

    ''' <summary>
    ''' This will cancel the BackgroundWorker.
    ''' </summary>
    Public Sub Cancel()
        _busy.[Set]() ' Resume worker if it is paused.
        MyWorker.CancelAsync() ' Cancel it.
    End Sub

End Class

#End Region


Entonces, desde el thread principal puedes hacer esto:

Código (vbnet) [Seleccionar]
Public Class Form1

   Private MyWorker As New BackgroundWork

   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
       MyWorker.StartBackgroundTask()
   End Sub

   Private Sub Button_Pause_Click() Handles Button_Pause.Click
       MyWorker.PauseWorker()
   End Sub

   Private Sub Button_Resume_Click() Handles Button_Resume.Click
       MyWorker.ContinueWorker()
   End Sub

End Class


Saludos








Crazy.sx

Cita de: ElektroSoft en 18 Diciembre 2013, 07:58 AM
Personálmente por cosas como esta nunca me gustó el BackGroundWorker.

La forma correcta de pausar/reusmir un BackgroundWorker es usando un ManualResetEvent:

EDITO: Fíjate que debes especificar manuálmente los lugares en donde el procedimiento se puede pausar (_busy.WaitOne), y esto debes especificarlo sólamente en el eventhandler DoWork.

Imports System.ComponentModel

Public Class BackgroundWork

    Private _busy As New Threading.ManualResetEvent(True)

    Private WithEvents MyWorker As New BackgroundWorker

    Public Sub StartBackgroundTask()
        MsgBox("Starting the Thread...")
        MyWorker.WorkerSupportsCancellation = True
        MyWorker.WorkerReportsProgress = True
        MyWorker.RunWorkerAsync()
    End Sub

    Private Sub MyWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) _
    Handles MyWorker.DoWork

        For i = 1 To 5
            _busy.WaitOne(Threading.Timeout.Infinite)
            MyWorker.ReportProgress(MsgBox("Thread is working... " & CStr(i)))
        Next i

    End Sub

    Private Sub MyWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) _
    Handles MyWorker.RunWorkerCompleted

        MsgBox("Thread Done!")

    End Sub

    Public Sub PauseWorker()

        If MyWorker.IsBusy Then
            _busy.Reset()
            MsgBox("Thread Paused!")
        End If

    End Sub

    Public Sub ContinueWorker()
        _busy.[Set]()
        MsgBox("Thread Resumed!")
    End Sub

End Class


EDITO 2: Un ejemplo mejor elaborado:

Código (vbnet) [Seleccionar]
' BackgroundWorker Example
'
' // By Elektro H@cker

#Region " Usage Examples "

'Public Class Form1

'    Private MyWorker As New BackgroundWork

'    Private Shadows Sub Load() Handles MyBase.Load
'        MyWorker.StartBackgroundTask()
'    End Sub

'    Private Sub Button_Pause_Click() Handles Button_Pause.Click
'        MyWorker.Pause()
'    End Sub

'    Private Sub Button_Resume_Click() Handles Button_Resume.Click
'        MyWorker.Resume()
'    End Sub

'    Private Sub Button_Cancel_Click() Handles Button_Cancel.Click
'        MyWorker.Cancel()
'    End Sub

'End Class

#End Region

#Region " BackgroundWorker "

Public Class BackgroundWork

    ''' <summary>
    ''' The BackgroundWorker object.
    ''' </summary>
    Private WithEvents MyWorker As New System.ComponentModel.BackgroundWorker

    ''' <summary>
    ''' ManualResetEvent object to pause/resume the BackgroundWorker.
    ''' </summary>
    Private _busy As New Threading.ManualResetEvent(True)


    ''' <summary>
    ''' This will start the BackgroundWorker.
    ''' </summary>
    Public Sub StartBackgroundTask()

        MsgBox("Starting the Thread...")
        MyWorker.WorkerSupportsCancellation = True
        MyWorker.WorkerReportsProgress = True
        MyWorker.RunWorkerAsync()

    End Sub

    ''' <summary>
    ''' This is the work to do on background.
    ''' </summary>
    Private Sub MyWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) _
    Handles MyWorker.DoWork

        For i = 1 To 5

            If MyWorker.CancellationPending = True Then
                e.Cancel = True
                Exit For
            Else
                _busy.WaitOne(Threading.Timeout.Infinite) ' Indicate that here can be paused the Worker.
                MyWorker.ReportProgress(
                    MsgBox("Thread is working... " & i)
                    )
            End If

        Next i

    End Sub

    ''' <summary>
    ''' This happens when the BackgroundWorker is completed.
    ''' </summary>
    Private Sub MyWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
    Handles MyWorker.RunWorkerCompleted

        If e.Cancelled = True Then
            MsgBox("Thread cancelled")

        ElseIf e.Error IsNot Nothing Then
            MsgBox("Thread error")

        Else
            MsgBox("Thread Done!")

        End If

    End Sub

    ''' <summary>
    ''' This will pause the BackgroundWorker.
    ''' </summary>
    Public Sub Pause()

        If MyWorker.IsBusy Then
            _busy.Reset()
            MsgBox("Thread Paused!")
        End If

    End Sub

    ''' <summary>
    ''' This will resume the BackgroundWorker.
    ''' </summary>
    Public Sub [Resume]()
        _busy.[Set]()
        MsgBox("Thread Resumed!")
    End Sub

    ''' <summary>
    ''' This will cancel the BackgroundWorker.
    ''' </summary>
    Public Sub Cancel()
        _busy.[Set]() ' Resume worker if it is paused.
        MyWorker.CancelAsync() ' Cancel it.
    End Sub

End Class

#End Region


Entonces, desde el thread principal puedes hacer esto:

Código (vbnet) [Seleccionar]
Public Class Form1

    Private MyWorker As New BackgroundWork

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        MyWorker.StartBackgroundTask()
    End Sub

    Private Sub Button_Pause_Click() Handles Button_Pause.Click
        MyWorker.PauseWorker()
    End Sub

    Private Sub Button_Resume_Click() Handles Button_Resume.Click
        MyWorker.ContinueWorker()
    End Sub

End Class


Saludos

Mmm... creo que seguiré usando la forma tradicional de usar hilos en background. Jeje.
Muchísimas gracias.
Destruir K. LOL