[Help] - Thread mit UI-Update

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von razor8.

    [Help] - Thread mit UI-Update

    Hey,
    also ich habe in einem Thread ein Listbox.Items.Add() command drin, jedoch wird das auf der Form micht angezeigt, da laut google, die auf einem anderem Thread liegen.
    Lösungsvorschläge sind : Control.BeginInvoke, Delegate , ... etc.

    Jedoch kapier ich diese Parameter nicht o,0 Ich versuche schon seit einem Tag den dreck :D.

    Könntet ihr mir ein Beispiel für ein ganz einfach code geben :)?

    VB.NET-Quellcode

    1. Dim _thread as new System.Threading.Thread(AddressOf Start)
    2. _tread.start
    3. Private Sub Start()
    4. do
    5. ListBox.Items.Add("Test")
    6. loop while ....
    7. End Sub


    mfg
    Hi,

    du mußt die Zugriffe auf die in Form1 und damit in einem anderen Thread befindlichen Controls synchronisieren. Dazu kannst du die .invokerequired Eigenschaft der ListBox benutzen. Erstell dir einen Delegaten, den du für den Fall =true instanzierst und der dir als Rücksprung dient. Über die Suchwörter Threadsicherer Zugriff delegate findest du in Google jede Menge Beispiele dazu.

    f0x
    Hi,
    kein Problem. Ein kleines Beispiel:

    VB.NET-Quellcode

    1. Private Delegate Sub myDelegate(ByVal MSG As String)
    2. ...
    3. Private Sub SafeAdd(ByVal MSG As String)
    4. If ListBox1.InvokeRequired Then
    5. Dim d As New myDelegate(AddressOf SafeAdd)
    6. ListBox1.Invoke(d, MSG)
    7. Else
    8. ListBox1.Items.Add(MSG)
    9. End If
    10. End Sub


    Du definierst dir eine Schablone für einen Delegaten der einen String als Parameter mit dabei hat. Die Logik für den Thread-sicheren Aufruf würde ich in einer kleinen Sub auslagern, ist übersichtlicher in der Verwendung. Zunächst fragst du ab, ob ein synchronisierter Zugriff gerade möglich ist (invokerequired). Falls dies nicht der Fall ist erstellst du dir eine neue Instanz deines Delegaten der eine Rücksprungadresse zur Sub selbst enthält. Diesen übergibst du dann, zusammen mit der ursprünglichen Nachricht (in dem Fall einfach nur ein String) an die Methode .invoke der ListBox. Im folgenden wird ein synchroner Zustand der beiden betreffenden Threads abgewartet und durch den Rücksprung erfolgt dann schliesslich das hinzufügen des items. Es ist klar daß aufgrund dieses Vorgehens ein Overhead entsteht und diese Art des Zugriffs ist selbstverständlich langsamer als wenn das alles nicht nötig wäre. Normalerweise sollte daher der Nutzen durch nebenläufige Programmstränge diesen Nachteil aufwiegen. Hoffe die Darstellung ist verständlich.

    Grüße,

    f0x
    Vielen vielen dank,
    nach mehrmaligen lesen, habe ich deinen zusammgefassten text einigermaßen verstanden, sodass ich mit hilfe deines Beispiels das Problem lösen konnte :).
    Funktioniert super.
    Ich bedanke mich nochmal herzlich und bei weiteren problem, werde ich mich an paradise wenden :)

    (gibt kein thnk button :P)

    mfg
    you're welcome, wie man neudeutsch sagt. Freue mich wenn es nun nicht nur einfach funktioniert sondern du auch verstanden hast warum. Dann wirst du beim nächsten Mal, wenn es auch keine ListBox ist, schon in der Lage sein das selbst zu lösen.

    Grüße,

    f0x

    gleiches problem

    hi leute,

    ich hab ein ähnliches problem: ich hab ein main-form und starte einen thread, vondem aus ich den text eines labels des mainforms ändern will(einige tausende mal). ich hab das beispiel oben versucht aber es erscheint einfach kein text...es passiert absolut nichts(bis auf den rest des threads).
    noch ein paar infos:
    corlib = dll
    cache ist eine klasse in der ich häufigverwendete variablen hab

    VB.NET-Quellcode

    1. Public Class main
    2. Public Sub main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    3. config.loadconfig()
    4. End Sub
    5. .
    6. .
    7. .
    8. Public Shared Sub updatetab_createextractedpatch_startprogress_button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles updatetab_createextractedpatch_startprogress_button.Click
    9. If Not Worker.Threads.create_extracted_patchThread.IsAlive Then
    10. Try
    11. Worker.Threads.create_extracted_patchThread.Start()
    12. Catch ex As Exception
    13. End Try
    14. End If
    15. End Sub
    16. End Class
    17. ...
    18. Public Class Worker
    19. ...
    20. Public Class Threads
    21. Public Shared create_extracted_patchThread As New Thread(AddressOf update.create_extracted_patch)
    22. Public Delegate Sub myDelegate(ByVal MSG As String)
    23. Public Shared Sub change_statuslabel_text(ByVal text As String)
    24. If main.main_statuslabel.InvokeRequired Then
    25. Dim d As New myDelegate(AddressOf change_statuslabel_text)
    26. main.main_statuslabel.Invoke(d, text)
    27. Else
    28. main.main_statuslabel.Text = text
    29. End If
    30. End Sub
    31. Public Shared Sub update_progressbar()
    32. If main.main_ProgressBar.InvokeRequired Then
    33. Dim d As New myDelegate(AddressOf update_progressbar)
    34. main.main_statuslabel.Invoke(d)
    35. Else
    36. main.main_ProgressBar.Value += 1
    37. main.main_statuslabel.Update()
    38. End If
    39. End Sub
    40. Public Shared Sub reset_progressbar(ByVal maximum As Integer)
    41. If main.main_ProgressBar.InvokeRequired Then
    42. Dim d As New myDelegate(AddressOf reset_progressbar)
    43. main.main_statuslabel.Invoke(d)
    44. Else
    45. main.main_ProgressBar.Maximum = maximum
    46. main.main_ProgressBar.Value = 0
    47. main.main_ProgressBar.Update()
    48. End If
    49. End Sub
    50. End Class
    51. Public Class update
    52. Public Shared Sub create_extracted_patch()
    53. If cache.updatetab.outputfoldername = Nothing Or cache.updatetab.UpdateFolder = Nothing Then
    54. Exit Sub
    55. End If
    56. If Not Directory.Exists(cache.ReleaseFolder & cache.updatetab.outputfoldername) Then
    57. Try
    58. Directory.CreateDirectory(cache.ReleaseFolder & cache.updatetab.outputfoldername)
    59. Catch ex As Exception
    60. End Try
    61. End If
    62. ...
    63. Threads.change_statuslabel_text("Indexing") 'hier sollte eigentlich der text des labels geändert werden
    64. Dim emptyfiles As List(Of String) = CorLib.FileSystemHelper.GetFiles(cache.updatetab.UpdateFolder, "all", True)
    65. Dim emptydirs As List(Of String) = CorLib.FileSystemHelper.GetDirectories(cache.updatetab.UpdateFolder, True)
    66. Dim allfiles As List(Of String) = CorLib.FileSystemHelper.GetFiles(cache.updatetab.UpdateFolder, "all", False)
    67. Threads.reset_progressbar(allfiles.Count + 1)
    68. For Each emptyfile In emptyfiles
    69. Threads.change_statuslabel_text("Deleting: " & emptyfile)
    70. Try
    71. File.Delete(emptyfile)
    72. Catch ex As Exception
    73. End Try
    74. Threads.update_progressbar()
    75. Next
    76. For Each emptydir In emptydirs
    77. Threads.change_statuslabel_text("Deleting: " & emptydir)
    78. Try
    79. Directory.Delete(emptydir)
    80. Catch ex As Exception
    81. End Try
    82. Threads.update_progressbar()
    83. Next
    84. Dim filestocopy As List(Of String) = CorLib.FileSystemHelper.GetFiles(cache.updatetab.UpdateFolder, "all", False)
    85. For Each filetocopy In filestocopy
    86. Threads.change_statuslabel_text("Copying: " & filetocopy)
    87. Try
    88. File.Copy(filetocopy, cache.ReleaseFolder & cache.updatetab.outputfoldername, True)
    89. Catch ex As Exception
    90. End Try
    91. Threads.update_progressbar()
    92. Next
    93. Threads.change_statuslabel_text("Extracted Patch successfully created!")
    94. End Sub
    95. End Class
    96. End Class


    hat jemand ne idee woran das liegt das es nicht funktioniert? wenn möglich (und zeitaufwand nicht zu größ) könnt ihr einfach den code so ändern das es läuft...und ichs versteh^^

    mfg razor8