Benutzer mit den meisten Antworten
Abbruch in BackgroundWorker DoWork

Frage
-
Hallo
Kann mir jemand auf die Sprünge helfen.
In BackgroundWorker_DoWork rufe ich eine Function in einer Schleife auf, die einen String zurückgibt.
Dieser String zeigt dieser einen Fehler an.Wenn dieser String <> "", will ich den BackgrounWorker beenden.
Ich denke das das mit e.Cancel richtig ist.
Ebenso übergebe ich in e.Result meinen String.
Dieser kommt leider nicht im BackgrounWorker_RunWorkerCompleted an.Meine Frage:
Wie beende ich in BackgroundWorker_DoWork richtig?
Wie kann ich dann noch einen String zurückgeben?Gruss Peter
Antworten
-
Hallo Peter,
um DoWork zu beenden, verlasse die Methode - also Return oder zum Ende der Methode kommen. Das RunWorkerCompleted Ereignis wird danach ausgeführt. Das Setzen von e.Cancel bzw. e.Result ist optional.
Ein Beispiel, das ich irgendwo anders mal gegeben hatte:
Imports System Imports System.ComponentModel Imports System.Diagnostics Imports System.Data.SqlClient Imports System.Windows.Forms Public Class BackgroundPollingForm Dim WithEvents pollingBackgroundWorker As New BackgroundWorker Public Sub New() InitializeComponent() pollingBackgroundWorker.WorkerSupportsCancellation = True pollingBackgroundWorker.WorkerReportsProgress = True End Sub Private Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click If pollingBackgroundWorker.IsBusy Then Debug.WriteLine("Worker stopped") pollingBackgroundWorker.CancelAsync() Else Debug.WriteLine("Worker started") pollingBackgroundWorker.RunWorkerAsync() End If End Sub Private Sub BackgroundPollingForm_Shown(sender As Object, e As System.EventArgs) Handles MyBase.Shown pollingBackgroundWorker.RunWorkerAsync() End Sub Private Sub BackgroundPollingForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing If e.Cancel = False AndAlso Me.pollingBackgroundWorker.IsBusy Then Me.pollingBackgroundWorker.CancelAsync() End If End Sub Private Sub pollingBackgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs) _ Handles pollingBackgroundWorker.DoWork Do While Not pollingBackgroundWorker.CancellationPending Try Using connection As New SqlConnection(My.Settings.AdventureWorksConnectionString) connection.Open() Dim command As New SqlCommand("SELECT COUNT(*) FROM Sales.SalesOrderHeader;", connection) Dim value = command.ExecuteScalar() pollingBackgroundWorker.ReportProgress(0, value) End Using Catch ex As Exception Debug.WriteLine("Worker exception " & ex.Message) e.Cancel = True Return End Try System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)) Loop End Sub Private Sub pollingBackgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) _ Handles pollingBackgroundWorker.ProgressChanged If Not Me.IsDisposed Then Debug.WriteLine("Worker ProgressChanged {0}", e.UserState) Me.InfoTextBox.Text = e.UserState.ToString() End If End Sub Private Sub pollingBackgroundWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) _ Handles pollingBackgroundWorker.RunWorkerCompleted If e.Error IsNot Nothing Then Debug.WriteLine("Worker exception " & e.Error.Message) ElseIf e.Cancelled Then Debug.WriteLine("Worker cancelled") Else Debug.WriteLine("Worker completed") End If End Sub End Class
Wobei die SQL Abfrage sinnfrei ist und durch Deine eigene Funktion / Schleife ersetzt würde.
Gruß Elmar
- Als Antwort markiert peter haus Freitag, 13. März 2015 19:18
Alle Antworten
-
Hallo Peter,
um DoWork zu beenden, verlasse die Methode - also Return oder zum Ende der Methode kommen. Das RunWorkerCompleted Ereignis wird danach ausgeführt. Das Setzen von e.Cancel bzw. e.Result ist optional.
Ein Beispiel, das ich irgendwo anders mal gegeben hatte:
Imports System Imports System.ComponentModel Imports System.Diagnostics Imports System.Data.SqlClient Imports System.Windows.Forms Public Class BackgroundPollingForm Dim WithEvents pollingBackgroundWorker As New BackgroundWorker Public Sub New() InitializeComponent() pollingBackgroundWorker.WorkerSupportsCancellation = True pollingBackgroundWorker.WorkerReportsProgress = True End Sub Private Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click If pollingBackgroundWorker.IsBusy Then Debug.WriteLine("Worker stopped") pollingBackgroundWorker.CancelAsync() Else Debug.WriteLine("Worker started") pollingBackgroundWorker.RunWorkerAsync() End If End Sub Private Sub BackgroundPollingForm_Shown(sender As Object, e As System.EventArgs) Handles MyBase.Shown pollingBackgroundWorker.RunWorkerAsync() End Sub Private Sub BackgroundPollingForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing If e.Cancel = False AndAlso Me.pollingBackgroundWorker.IsBusy Then Me.pollingBackgroundWorker.CancelAsync() End If End Sub Private Sub pollingBackgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs) _ Handles pollingBackgroundWorker.DoWork Do While Not pollingBackgroundWorker.CancellationPending Try Using connection As New SqlConnection(My.Settings.AdventureWorksConnectionString) connection.Open() Dim command As New SqlCommand("SELECT COUNT(*) FROM Sales.SalesOrderHeader;", connection) Dim value = command.ExecuteScalar() pollingBackgroundWorker.ReportProgress(0, value) End Using Catch ex As Exception Debug.WriteLine("Worker exception " & ex.Message) e.Cancel = True Return End Try System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)) Loop End Sub Private Sub pollingBackgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) _ Handles pollingBackgroundWorker.ProgressChanged If Not Me.IsDisposed Then Debug.WriteLine("Worker ProgressChanged {0}", e.UserState) Me.InfoTextBox.Text = e.UserState.ToString() End If End Sub Private Sub pollingBackgroundWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) _ Handles pollingBackgroundWorker.RunWorkerCompleted If e.Error IsNot Nothing Then Debug.WriteLine("Worker exception " & e.Error.Message) ElseIf e.Cancelled Then Debug.WriteLine("Worker cancelled") Else Debug.WriteLine("Worker completed") End If End Sub End Class
Wobei die SQL Abfrage sinnfrei ist und durch Deine eigene Funktion / Schleife ersetzt würde.
Gruß Elmar
- Als Antwort markiert peter haus Freitag, 13. März 2015 19:18
-
Hallo Elmar,
wieder mal vielen Dank.
Ich werde dein Codeschnipsel gleich mal vornehmen.Ich verstehe gerade immer weniger.
Ich teste mit dem Stückchen Code unten.
Bei der Zeile BackgroundWorker1.ReportProgress(i, DateTime.Now) kein Problem.Bei den Zeilen
s = "Mein String " & DateTime.Now
BackgroundWorker1.ReportProgress(i, s)
und
BackgroundWorker1.ReportProgress(i, "Working---")
geht nichts mehr. Meldung: Ein Aufrufziel hat einen Ausnahmefehler verursacht.gibt es da eine Erklärung?
Vielen Dank.
PeterPrivate Sub backgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim s As String
Dim start As DateTime = DateTime.Now
e.Result = ""For i As Integer = 0 To 30
System.Threading.Thread.Sleep(50)
BackgroundWorker1.ReportProgress(i, DateTime.Now)
's = "Mein String " & DateTime.Now
'BackgroundWorker1.ReportProgress(i, s)'BackgroundWorker1.ReportProgress(i, "Working---")
If i >= 10 Then
e.Result = "MyCancel"
e.Cancel = True
Return
End IfIf BackgroundWorker1.CancellationPending Then
e.Cancel = True
Return
End If
NextDim duration As TimeSpan = DateTime.Now - start
e.Result = "Duration: " + duration.TotalMilliseconds.ToString() + " ms."
End Sub -
Hallo Peter,
da Du den EventHandler nicht zeigst, kann ich nur vermuten...
In UserState kann man alles reinpacken, weil es vom Type System.Object ist, aber bei der Verarbeitung muss man es richtig auspacken, sonst knallt es. Erweitert man in meinem Beispiel die Übergabe zu:
pollingBackgroundWorker.ReportProgress(0, value) ' Weitere... pollingBackgroundWorker.ReportProgress(CType(value, Integer), "Hallo") pollingBackgroundWorker.ReportProgress(CType(value, Integer), DateTime.Now) pollingBackgroundWorker.ReportProgress(CType(value, Integer), value)
so könnte man das z. B. so tun:
Private Sub pollingBackgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) _ Handles pollingBackgroundWorker.ProgressChanged If Not Me.IsDisposed Then If TypeOf e.UserState Is Integer Then Debug.WriteLine("UserState is an integer.") ElseIf TypeOf e.UserState Is DateTime Then Debug.WriteLine("UserState is a date.") ElseIf TypeOf e.UserState Is String Then Debug.WriteLine("UserState is a string.") End If Debug.WriteLine("Worker ProgressChanged {0}", e.UserState) Me.InfoTextBox.Text = e.UserState.ToString() End If End Sub
Meine Ausgabe funktioniert unabhängig davon, da sie via ToString() aus allem einen String macht. In den Fällen, in denen es auf den Typ ankommt, muss man wie oben testen und via CType umwandeln oder aber TryCast verwenden. Am besten definiert man jedoch eine Klasse, die alle notwendigen Elemente als Eigenschaften hat, so dass man UserState direkt via DirectCast umwandeln kann.
Gruß Elmar