Listbox und Multithreading

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von zauber777.

    Listbox und Multithreading

    Hallo,

    ich habe eine Verständnis-Frage zum Thema Multithreading.
    In meiner Form habe ich eine Listbox, welche ich beim Laden mit ein paar Einstellungen fülle.
    Über einen Button aktiviere ich dann die ausgewählte Einstellung.
    Leider friert mein Programm ein, bis es die Einstellung komplett erledigt hat. Deswegen hatte ich mir überlegt, dass ich es über Multithreading lösen könnte!? Hiermit habe ich jedoch noch keine Erfahrung daher schreibe ich hier.

    Bisher sieht mein Code wie folgt aus :

    Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Imports System
    4. Imports System.Net
    5. Imports System.Net.Sockets
    6. Imports System.Runtime.InteropServices
    7. Imports System.Net.NetworkInformation
    8. Imports System.IO
    9. Imports System.Text
    10. Imports System.Diagnostics
    11. Imports System.ComponentModel
    12. Imports System.Drawing
    13. Imports System.Management
    14. Public Class Einstellung_Allgemein
    15. Dim ToolTextListe As New List(Of String)
    16. Private Sub Einstellung_Allgemein_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    17. ListBox1.Items.Add("Einstellung1")
    18. ToolTextListe.Add("bla bla 1")
    19. ListBox1.Items.Add("Einstellung 2")
    20. ToolTextListe.Add("bla bla 2")
    21. ...
    22. End Sub
    23. Private allActions As New List(Of Action) From {AddressOf Einstellung1, AddressOf Einstellung2}
    24. Private Sub Auswahlaktivieren_Click(sender As Object, e As EventArgs) Handles Auswahlaktivieren.Click
    25. Dim index = ListBox1.SelectedIndex
    26. If index > -1 AndAlso index < allActions.Count Then
    27. allActions(index).Invoke()
    28. End If
    29. End Sub
    30. Private Sub Einstellung1()
    31. ...
    32. End Sub
    33. Private Sub Einstellung2()
    34. ...
    35. End Sub


    Wenn ich nun Multithreading machen möchte, dann müsste ich doch auch mit "Private Sub Einstellung1()" arbeiten und in diesem dann auf den schon vorhandenen hinweisen!? Dies geht aber nicht...

    Ich hoffe ihr versteht mein Problem und könnt mir vielleicht helfen!?
    Ah :) Danke.

    habe ich geändert. Nur bekomme ich nun die Fehlermeldung
    "Fehler 1 Für den Parameter "callback" von "Public Overridable Function BeginInvoke(callback As System.AsyncCallback, object As Object) As System.IAsyncResult" wurde kein Argument angegeben."

    Den Parameter "callback" habe ich doch nirgends gesetzt!?
    Du musst Du hier einen Delegaten angeben, der auf eine Funktion zeigt, die ausgeführt wird, sobald die Aufgabe erledig ist. Siehe dazu auch diesen Artikel: msdn.microsoft.com/en-us/library/2e08f6yc(VS.71).aspx

    EDIT: Falsche Informationen entfernt.





    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „SpaceyX“ ()

    man soll schon einen callback angeben - nicht nothing. Weil auf msdn steht iwo, es ist unbedingt notwendig, dass delegat.EndInvoke aufgerufen wird.
    Das macht ja auch kein groß problem, denn delegat.EndInvoke ist grad ein passender callback:

    VB.NET-Quellcode

    1. dim delegat=new Action(Of String)(Addressof aStringSub)
    2. delegat.BeginInvoke("Hallo Welt",addressof delegat.EndInvoke, Nothing) 'nebenläufiger Aufruf der aStringSub

    @ErfinderDesRades Ja, da hast Du recht (Recht?). Hatte hier wohl falsche Fakten im Kopf. Werde oben ausbessern, bzw. wegstreichen.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    @ErfinderDesRades

    Ich hab mir nochmals Gedanken darüber gemacht und auch nochmals Einiges darüber gelesen. Dass EndInvoke aufgerufen werden sollte, daran möchte ich nicht rütteln. Jedoch zweifle ich an Deiner Implementation des Musters.

    Dein Code:

    VB.NET-Quellcode

    1. dim delegat=new Action(Of String)(Addressof aStringSub)
    2. delegat.BeginInvoke("Hallo Welt",addressof delegat.EndInvoke, Nothing) 'nebenläufiger Aufruf der aStringSub


    Ich denke, dies ist nicht richtig. In jedem Dokument, welches ich die letzte Stunde gelesen hab, finde ich nirgendwo eine Implementation wie diese.

    Der korrekte Aufruf von EndInvoke sollte so aussehen:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _a As Action = Sub() Threading.Thread.Sleep(100)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. _a.BeginInvoke(AddressOf _a_EndInvoke, Nothing)
    5. End Sub
    6. Private Sub _a_EndInvoke(ar As IAsyncResult)
    7. _a.EndInvoke(ar)
    8. End Sub
    9. End Class


    Der Methode EndInvoke muss, so verstehe ich es, als Parameter eine Instanz von IAsyncResult übergeben werden, um den Vorgang korrekt abzuschließen. Evtl. kannst Du mal kurz dazu Stellung nehmen und mich ggf. korrigieren oder mir Stellen nennen, wo ein Muster, wie Du es zeigst, angewandt wird. So, wie Du es zeigst, erscheint es mir irgendwie sinnlos.

    Als Kurzversion:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _a As Action = Sub()
    3. Threading.Thread.Sleep(100)
    4. End Sub
    5. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    6. _a.BeginInvoke(Sub(x) _a.EndInvoke(x), Nothing)
    7. End Sub
    8. End Class
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Also so ganz versteh ich es noch nicht. Mein Code sieht jetzt wie folgt aus :

    Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Imports System
    4. Imports System.Net
    5. Imports System.Net.Sockets
    6. Imports System.Runtime.InteropServices
    7. Imports System.Net.NetworkInformation
    8. Imports System.IO
    9. Imports System.Text
    10. Imports System.Diagnostics
    11. Imports System.ComponentModel
    12. Imports System.Drawing
    13. Imports System.Management
    14. Public Class Einstellung_Allgemein
    15. Dim ToolTextListe As New List(Of String)
    16. Private Sub Einstellung_Allgemein_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    17. ListBox1.Items.Add("Einstellung1")
    18. ToolTextListe.Add("bla bla 1")
    19. ListBox1.Items.Add("Einstellung 2")
    20. ToolTextListe.Add("bla bla 2")
    21. ...
    22. End Sub
    23. Private allActions As New List(Of Action) From {AddressOf Einstellung1, AddressOf Einstellung2}
    24. Private Sub Auswahlaktivieren_Click(sender As Object, e As EventArgs) Handles Auswahlaktivieren.Click
    25. Dim index = ListBox1.SelectedIndex
    26. If index > -1 AndAlso index < allActions.Count Then
    27. allActions(index).BeginInvoke()
    28. End If
    29. End Sub
    30. Private Sub Einstellung1()
    31. ...
    32. Einstellung1.EndInvoke()
    33. End Sub
    34. Private Sub Einstellung2()
    35. ...
    36. Einstellung2.EndInvoke()
    37. End Sub
    @SpaceyX

    Das von EDR ist schon richtig, das was du gemacht hast, ist wie das hier:

    VB.NET-Quellcode

    1. Private callBack As Action(Of String)
    2. Private Sub Test(pText As String)
    3. 'EndInvoke aufrufen
    4. DoIt(callBack)
    5. 'Methode aufrufen
    6. DoIt(AddressOf ZweiterTest)
    7. End Sub
    8. 'Das hier wäre Endinvoke
    9. Private Sub DoIt(pCallBack As Action(Of String))
    10. End Sub
    11. Private Sub ZweiterTest(pText As String)
    12. 'Hier dann EndInvoke aufrufen
    13. DoIt(callBack)
    14. End Sub


    bzw auch sowas (was ich öfter sehe):

    Quellcode

    1. Private Sub blabla()
    2. Dim abc As New List(Of String)
    3. abc.Select(AddressOf Char.IsLetter)
    4. abc.Select(AddressOf getItem)
    5. End Sub
    6. Private Function getItem(pText As Char) As Boolean
    7. Return Char.IsLetter(pText)
    8. End Function


    Also im Grunde rufst du eine zweite Methode auf die dann einfach EndInvoke aufruft, anstatt EndInvoke direkt aufrufen zu lassen, nach beendigung von "_a", obwohl beide die selbe Signatur aufweisen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RushDen“ ()

    @RushDen Danke Dir und auch nochmal ein "Nix für ungut" an @ErfinderDesRades Ich war hier schwer auf dem falschen Dampfer. Kann ja mal passieren. Hat auch nur nen halben Tag gedauert, bis der Groschen gefallen ist.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Hihi!

    Das ist genau der Effekt, weswegen ich trotz gelegentlicher Peinlichkeiten immer meine Klappe bedenkenlos aufreisse: Wennich auffm falschen Dampfer bin, kriege ich die Korrektur und egal ob peinlich hab ich genau dann den größten Lern-Gewinn von allen :D
    "Der Tor sagt, wasser weiß, und der Weise weiß, wasser sagt." Da es keine Weisen gibt, also immer fröhlich raus damit - macht zwar nicht weise, aber man lernt was dabei.

    /offtopic
    Leider hänge ich noch immer an dem Problem... Ich habe im Post-11 den Code gepostet.

    Egal, wie ich es schiebe und wende. ich bekomme immer wieder die Fehlermeldung "Fehler 1 Für den Parameter "callback" von "Public Overridable Function BeginInvoke(callback As System.AsyncCallback, object As Object) As System.IAsyncResult" wurde kein Argument angegeben."
    ja, das liegt daran, dass du der BeginInvoke-Funktion keinen callback angibst.
    mach also so:

    VB.NET-Quellcode

    1. dim delegat as Action=allActions(index)
    2. delegat.BeginInvoke(addressof delegat.EndInvoke, Nothing)
    feddich

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ich bin, glaube ich, einfach zu doof dazu...

    Ich habe die 2 Zeilen von EDR im Load, im Allgemeinen, im Button und in der "Private Sub Einstellung1" probiert.

    Ich bekomme immer wieder die Fehlermeldungen, dass auf die lokale Variable "Index" nicht zugegriffen werden kann und es bleibt auch bei der Fehlermeldung "Fehler 1 Für den Parameter "callback" von..."