Problem mit Event und verschiedenen Task

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 45 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Await Threading.Tasks.Task.Run scheint nicht zwangsläufig einen eigenständigen Thread zu starten. Bin aber nicht genügend in der Materie drin, um es erklären zu können.
    Zumindest wird die Oberfläche durch eine lange Aufgabe nicht blockiert und die Oberfläche bleibt reaktionsfähig. Aber, dass das jetzt per Definition nicht unbedingt ein neuer Thread ist, das wäre mir neu.
    Und so bleibt weiterhin im Dunkeln, warum ein Thread zu einer UnhandledException führen kann, ein (zu einfacher?) Task hingegen zu einer ThreadException, die ja nur im GUI-Thread entstehen kann, laut Microsoft.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    So habe nun meine Klasse für das kopieren und zippen gesäubert usw. Habe dann bei testen festgestellt, das ein RaiseEventHandler nicht passte.

    RaiseEvent NotificationsID(Notification.Failure, propertyValues.errorHdd)
    Hier wurde bei einem Fehler der Timer nicht gestartet
    ALT:

    VB.NET-Quellcode

    1. Private Sub Mitteilungen(ByVal var As CopyZip.Meldung, FailuerHDD As String) Handles copyzip.MeldungsID
    2. lblFormName.ForeColor = Color.Firebrick
    3. timerMessages.Start()
    4. ...


    Neu:

    VB.NET-Quellcode

    1. Private Sub Mitteilungen(ByVal var As CopyZip.Notification) Handles copyzip.NotificationsID
    2. lblFormName.ForeColor = Color.Firebrick
    3. timerMessages.Start()
    4. ...


    Die bereinigte Klasse.
    Spoiler anzeigen

    Auszug aus dem MainForm

    VB.NET-Quellcode

    1. Public Class frmMain
    2. Private logger As New Logging()
    3. Private drivehelper As New DriveManager()
    4. Private xmlhelper As New XmlManager()
    5. Private WithEvents copyzip As New CopyZip(drivehelper)
    6. Private enterPressed As Boolean = False
    7. Public Sub New()
    8. AddHandler Application.ThreadException, AddressOf ExceptionHandlerForErrors
    9. AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf ExceptionHandlerForErrors
    10. InitializeComponent()
    11. CheckXmlFile()
    12. End Sub
    13. Private Sub ExceptionHandlerForErrors(sender As Object, e As System.Threading.ThreadExceptionEventArgs)
    14. ShowError(e.Exception)
    15. End Sub
    16. Private Sub ExceptionHandlerForErrors(sender As Object, e As System.UnhandledExceptionEventArgs)
    17. ShowError(DirectCast(e.ExceptionObject, Exception))
    18. End Sub
    19. Private Sub ShowError(ex As Exception)
    20. logger.ExceptionToFile("Ein Fehler ist aufgetreten!" & Environment.NewLine & ex.Message)
    21. MessageBox.Show("Ein unerwarteter Fehler ist aufgetreten!" & Environment.NewLine & ex.Message, "Wichtige Info", MessageBoxButtons.OK, MessageBoxIcon.Warning)
    22. End Sub



    VB.NET-Quellcode

    1. Public Class CopyZip
    2. '' Definiert die verschiedenen Benachrichtigungstypen
    3. Friend Enum Notification
    4. Copy
    5. Zip
    6. Both
    7. End Enum
    8. '' ManagerClass für Laufwerke und Pfadinformationen
    9. Private propertyValues As New DriveManager()
    10. Private Property HDDS As DriveInfo() = DriveInfo.GetDrives()
    11. 'Friend Event FailureHDD(FailureHDD As String)
    12. Friend Event NotificationsID(NotificationID As Notification)
    13. Friend Event ZipFileReport(ReportedFileName As String)
    14. Friend Event CopyFileReport(ReportedFileName As String)
    15. Public Sub New(propInfo As DriveManager)
    16. propertyValues = propInfo
    17. End Sub
    18. ''' <summary>
    19. ''' Überprüft die Verfügbarkeit der Laufwerke und meldet ggf. einen Fehler.
    20. ''' </summary>
    21. Private Sub CheckDrives()
    22. Dim isSourcePathReady As Boolean = propertyValues.IsDriveReady(propertyValues.SourcePath)
    23. Dim isTargetCopyPathReady As Boolean = propertyValues.IsDriveReady(propertyValues.TargetCopyPath)
    24. Dim isTargetZipPathReady As Boolean = propertyValues.IsDriveReady(propertyValues.TargetZipPath)
    25. Dim affectedDrive As String = Nothing
    26. If Not isSourcePathReady Then
    27. affectedDrive = propertyValues.SourcePath
    28. ElseIf Not isTargetCopyPathReady Then
    29. affectedDrive = propertyValues.TargetCopyPath
    30. ElseIf Not isTargetZipPathReady Then
    31. affectedDrive = propertyValues.TargetZipPath
    32. End If
    33. '' Auskommentiert, weil zur Zeit nicht nötig ist, da auf dem MainForm abgefangen wird.
    34. 'If Not String.IsNullOrEmpty(affectedDrive) Then
    35. ' RaiseEvent FailureHDD(affectedDrive)
    36. 'End If
    37. End Sub
    38. ''' <summary>
    39. ''' Ruft den asyncronen Vorgang basierend auf dem ausgewählten Typ auf.
    40. ''' </summary>
    41. Friend Sub StartCopyZipThreads(SelectedCopytype As Integer)
    42. Select Case SelectedCopytype
    43. Case Is = 0
    44. CopyAsync()
    45. Case Is = 1
    46. ZipAsync()
    47. Case Is = 2
    48. CopyZipAsync()
    49. End Select
    50. End Sub
    51. ''' <summary>
    52. ''' CopyAsync & ZipAsync & CopyZipAsync
    53. ''' Startet jeweils den asyncronen Kopier- oder Zip-Vorgang basierend auf dem ausgewählten Typ.
    54. ''' </summary>
    55. Private Async Sub CopyAsync()
    56. Await Threading.Tasks.Task.Run(Function() DoFileCopy())
    57. RaiseEvent NotificationsID(Notification.Copy)
    58. End Sub
    59. Private Async Sub ZipAsync()
    60. Await Threading.Tasks.Task.Run(Function() DoFileZip())
    61. RaiseEvent NotificationsID(Notification.Zip)
    62. End Sub
    63. Private Async Sub CopyZipAsync()
    64. Await Threading.Tasks.Task.Run(Function() DoFileCopy())
    65. Await Threading.Tasks.Task.Run(Function() DoFileZip())
    66. RaiseEvent NotificationsID(Notification.Both)
    67. End Sub
    68. ''' <summary>
    69. ''' Führt das Zippen der Dateien aus.
    70. ''' </summary>
    71. Private Function DoFileZip() As Boolean
    72. CheckDrives()
    73. Dim FiledateSuffix As String = Date.Now.ToString("-HH_mm")
    74. If Not Directory.Exists(propertyValues.TargetZipPath) Then Directory.CreateDirectory(propertyValues.TargetZipPath)
    75. RaiseEvent ZipFileReport(propertyValues.TargetZipPath & FiledateSuffix)
    76. ZipFile.CreateFromDirectory(propertyValues.SourcePath, propertyValues.TargetZipPath & FiledateSuffix & ".zip", CompressionLevel.Fastest, False)
    77. If Not System.IO.Directory.GetFiles(propertyValues.TargetZipPath).Length = 0 Then
    78. Else
    79. IO.Directory.Delete(propertyValues.TargetZipPath)
    80. End If
    81. Return True
    82. End Function
    83. ''' <summary>
    84. ''' Führt das Kopieren der Dateien aus.
    85. ''' </summary>
    86. Private Function DoFileCopy() As Boolean
    87. CheckDrives()
    88. Dim NewSourcePath As New IO.DirectoryInfo(propertyValues.SourcePath), file As IO.FileInfo
    89. If IO.Directory.Exists(propertyValues.TargetCopyPath) = False Then IO.Directory.CreateDirectory(propertyValues.TargetCopyPath)
    90. For Each file In NewSourcePath.GetFiles()
    91. RaiseEvent CopyFileReport(propertyValues.TargetCopyPath & "\" & file.Name)
    92. IO.File.Copy(file.FullName.ToString, propertyValues.TargetCopyPath & "\" & file.Name.ToString, True)
    93. Next
    94. For Each subdir In NewSourcePath.GetDirectories()
    95. Call Subfoldercopy(subdir.FullName.ToString, propertyValues.TargetCopyPath & "\" & subdir.Name.ToString, True)
    96. Next
    97. Return True
    98. End Function
    99. ''' <summary>
    100. ''' Kopiert Dateien und Verzeichnisse rekursiv.
    101. ''' </summary>
    102. Private Sub Subfoldercopy(ByVal SubSource As String, ByVal Destination As String, ByVal Overwrite As Boolean)
    103. CheckDrives()
    104. Dim subdir As IO.DirectoryInfo, diSubSource As New IO.DirectoryInfo(SubSource), file As IO.FileInfo
    105. If IO.Directory.Exists(Destination) = False Then IO.Directory.CreateDirectory(Destination)
    106. For Each file In diSubSource.GetFiles()
    107. RaiseEvent CopyFileReport(file.FullName)
    108. If (IO.File.Exists(Destination & "\" & file.Name.ToString) AndAlso Overwrite = False) = False Then _
    109. IO.File.Copy(file.FullName.ToString, Destination & "\" & file.Name.ToString, Overwrite)
    110. Next
    111. For Each subdir In diSubSource.GetDirectories()
    112. Call Subfoldercopy(subdir.FullName.ToString, Destination & "\" & subdir.Name.ToString, Overwrite)
    113. Next
    114. End Sub
    115. End Class

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    VaporiZed schrieb:

    Await Threading.Tasks.Task.Run scheint nicht zwangsläufig einen eigenständigen Thread zu starten.
    Es genügt doch, schreibend auf die GUI zuzugreifen.
    Ein Einzeiler:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    :cursing: Solange keiner hier schlüssig erklären kann, warum dann solche Exceptions im ThreadException-EventHandler und nicht im UnhandledException-EventHandler landen, bleibt die Unklarheit bestehen.

    Da bringt diese stackoverflow-Diskussion schon etwas mehr Licht ins Dunkel. Da heißt es zwar auch Because Tasks != Threads. - aber das ist nicht sonderlich zielführend, auch wenn es meinen Punkt unterstützt :whistling:
    Auch Microsoft sagt was dazu. Letztenendes wohl: Ein exceptionerzeugender Task gibt seine Infos inkl. Exception an den aufrufenden Thread (z.B. GUI-Thread) zurück und so landet die Exception, wenn sie nicht behandelt wird, im ThreadException-EventHandler und nicht wie eine Exception aus einem autarken Thread im UnhandledException-EventHandler.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Der war gut. :thumbup:
    Wenn ich mein Beispiel aus Post #44 ohne Debugger ausführe, kommt der besagte Text im ListBox an. :S

    Und dann gibt es noch die Exception-Einstellungen im Debugger.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!