Threadübergreifend in ListBox schreiben!

  • VB.NET

Es gibt 38 Antworten in diesem Thema. Der letzte Beitrag () ist von Manschula.

    Threadübergreifend in ListBox schreiben!

    Hallo, ich habe mehrere Threads, und in meinem Form1 Hauptthread habe ich eine ListBox.

    Da schreibe ich alle wichtige meldungen rein, also eigentlich so eine art programmlog.
    Nun zu meinem Problem: Wenn ich in Form1 (also dem mainthread) meldungen ausgeben lasse, funktioniert alles.

    Versuche ich das ganze nun aus einem anderen Thread heraus, so geht er korrekt in die funktion und dort entsteht auch kein fehler, aber in der Listbox ist nix zu sehen!

    Habt ihr da eine Idee wo der fehler liegt?
    hach :) perfekt :) danke... ich teste gleich mal ^^
    arbeite noch nicht lange mit multithreading und bisher haben die threads nicht zusammenarbeiten müssen, also kamen da bisher noch keine probleme auf ;) und somit war mir das alles unbekannt...

    EDIT://
    habe jetzt alles nach anleitung in der Hilfe gemacht...

    VB.NET-Quellcode

    1. Delegat Sub delegat_c(ByVal text As String)
    2. Dim c1 As New Form1
    3. Dim c_meldung As delegat_c = AddressOf c1.messages


    und dann habe ich das ganze mit:

    VB.NET-Quellcode

    1. c_meldung.Invoke("Test")


    aufgerufen... aber ohne erfolg.. er geht in die funktion aber in der ListBox steht "Test" nicht drin...

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „buettner123“ ()

    Der gesammte code wäre etwas viel aber hier die relevaten teile:

    Form1 (SubMeldeLog)

    VB.NET-Quellcode

    1. Dim dummy As Object = ""
    2. Sub Melde_log(ByVal Meldung As String)
    3. SyncLock dummy
    4. Dim time As Date = TimeOfDay
    5. ListBox1.Items.Add("[" & time & ":] " & Meldung)
    6. ListBox1.SelectedIndex = ListBox1.Items.Count - 1
    7. Meldung = ""
    8. End SyncLock
    9. End Sub


    Der andere Thread:

    VB.NET-Quellcode

    1. Class aktion
    2. Delegate Sub d_melde_log(ByVal Meldung As String)
    3. Dim c_meldung As New Form1
    4. Sub Start()
    5. Dim melde_log_d As New d_melde_log(AddressOf c_meldung.Melde_log)
    6. melde_log_d.Invoke("TEST")
    7. End Sub
    8. End Class


    Hab auch schon die deklarationen von den einzelen sachen außerhalb der klasse usw getestet... aber es will nicht gehen!
    Dim c_meldung As delegat_c = AddressOf c1.messages
    so kenn ich das gar nicht, sondern so:
    Dim c_meldung As New delegat_c ( AddressOf c1.messages)
    Me.Control.Invoke(c_Meldung,Text)
    Control durch dein Control ersetzen...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    habe das jetzt so umgebaut...

    VB.NET-Quellcode

    1. Me.c_meldung.Invoke(melde_log_d, "Test")
    (siehe beitrag oben drüber)

    Quellcode

    1. Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde.


    ?( dadurch kann ich mein komplettes programm nicht weitermachen (also durch dieses problem mit den delegaten..., den jetzt taucht das ständig auf, dass ich die brauchen würde...)

    EDIT://
    Smoove, deine Lösung würde ich dann auch nur als letzten ausweg in erwägung ziehen :D wenn es anders geht wäre mir dann schon lieber :D
    so kenn ich das gar nicht, sondern so:
    Dim c_meldung As New delegat_c ( AddressOf c1.messages)
    Me.Control.Invoke(c_Meldung,Text)
    Control durch dein Control ersetzen...

    das Control muss unterdessen bereits erstellt sein(also in Form-Load kann probleme verursachen...)...
    oder die kurze Lösung , die Augenkrebs und Wutausbrüche bei Programmierern auslöst:

    vollkommen richtig...->also nicht machen, denn wenn es nachher 1 oder 2 mal nicht funktioniert, dann kann das probleme verursachen...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    jvbsl schrieb:

    so kenn ich das gar nicht, sondern so:
    Dim c_meldung As New delegat_c ( AddressOf c1.messages)
    Me.Control.Invoke(c_Meldung,Text)
    Control durch dein Control ersetzen...

    das Control muss unterdessen bereits erstellt sein(also in Form-Load kann probleme verursachen...)...

    Das Form1 ist schon komplett aufgebaut und die ListBox hat auch schon Einträge, der neue Thread wird nämlich erst erstellt, wenn der user einen button geklickt hat (er fungiert dann als arbeitsthread, und soll halt ab und zu mal sagen, was er denn gerade macht)...
    Ich kann es momentan leider net gut erklären, aber das Beispiel müsste zeigen.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Delegate Sub SetLog(ByVal Text As String)
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. Dim text As String = Nothing
    5. text = "Hello World"
    6. If (Me.TextBox1.InvokeRequired) Then
    7. Me.Invoke(New SetLog(AddressOf SetText), New Object() {text})
    8. Else
    9. Me.TextBox1.Text = text
    10. End If
    11. End Sub
    12. Private Sub SetText(ByVal text As String)
    13. Me.TextBox1.Text = text
    14. End Sub
    15. End Class


    Der untere teile im Button-Click ab InvokeRequired habe ich aus einem Event das bei mir Programm ausgelöst wird, wenn der Thread ne Log-datei schreibt.

    jvbsl schrieb:

    hast du denn deinen Code endlich mal so umprogrammiert, dass meiner drinne steht?

    ja klar... hab das ja direkt umgebaut...
    In der Hilfe steht zu meinem fehler, dass dieser auftritt, wenn man versucht mit einem thread auf ein windowsforms element zuzugreifen, was nicht von diesem erstellt wurde und als hinweis steht dann: invoke benutzen

    Aber das mache ich ja...

    VB.NET-Quellcode

    1. Delegate Sub d_melde_log(ByVal Meldung As String)
    2. Dim c_meldung As New Form1
    3. Dim melde_log_d As New d_melde_log(AddressOf Form1.Melde_log)
    4. Me.c_meldung.Invoke(melde_log_d, "Test")



    Da bekomme ich diesen Fehler:

    Quellcode

    1. Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde.


    EDIT://
    kann es evlt daran liegen, das ich das ganze invoke in einer anderen klasse als form1 versuche? (auch mein Melde_log, welches die ListBoxen füllt liegt in klass Form1, ich versuche aber in einer anderen klasse diese funktion auszulösen ?( )
    Das selbe Problem hatte ich am Anfang bei den Threads auch.

    Der Aufruf der das Ergebnis übergibt muss in der selben Klasse sein, wie das Control.

    VB.NET-Quellcode

    1. If (Me.Control.InvokeRequired) Then
    2. Me.Invoke(New SetLog(AddressOf SetText), New Object() {text})
    3. Else
    4. Me.Control.Text = text
    5. End If
    Dim c_meldung As New Form1

    du erstellst das Formular erst dann, wann du die Methode aufrufen willst und dieses ist noch nichtmal angezeigt...das kann nicht funktionieren...
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    jvbsl schrieb:

    Dim c_meldung As New Form1

    du erstellst das Formular erst dann, wann du die Methode aufrufen willst und dieses ist noch nichtmal angezeigt...das kann nicht funktionieren...

    ja und wo soll ich es dann und vorallem wann erzeugen? Form1 ist fertig aufgebaut die listboxen existieren.
    (sry wenn ich aufem schlauch steh ?( )

    Ich habe 2 klassen:
    Form1 (meine start und einstiegsklasse)
    ist Form1 aufgebaut und der user klickt einen button, wird ein neues thread von meiner klasse aktion erzeugt
    in dieser klasse aktion, will ich nun den Sub Melde_Log in der Klasse Form1 aufrufen, um eine Meldung hinzuzufügen..

    Mein delegat usw deklariere ich bei der klasse aktion und rufe diesen auch dort auf, dort steht auch das Dim c_meldung As New Form1 !?

    ist dabei ein fehler? :S so hatte ich das jetzt verstanden das ich es machen muss...