Subthread soll Sub in Mainthread aufrufen

  • VB.NET

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

    Subthread soll Sub in Mainthread aufrufen

    Guten Tag,

    Folgendes Problem:
    Ich möchte einen Subthread starten, der in einer Endlosschleife läuft und dort ständig Daten aktualisiert.
    Wenn im Subthread Daten aktualisiert wurden, soll dieser Meldung an den Mainthread machen.
    Der Mainthread soll dann mit den Daten eine Anzeige aktualisieren.

    Ich denke man macht das ganze mit Events, oder?
    Falls ja, wie kann ich von einem Subthread aus die Sub UpdateAnzeigen() im Mainthread aufrufen?

    Quellcode

    1. Option Strict On
    2. Imports System.Threading
    3. Public Class Main
    4. Public daten As Integer
    5. Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    6. Dim Subthread1 As New Threading.Thread(AddressOf Endlosschleife)
    7. Subthread1.Start()
    8. End Sub
    9. Private Sub Endlosschleife()
    10. Do
    11. Thread.Sleep(100)
    12. '...
    13. daten = 5 'daten wurden hier aktualisiert
    14. '...
    15. Loop
    16. End Sub
    17. Private Sub UpdateAnzeige()
    18. LblAnzeige.Text = daten.ToString
    19. End Sub
    20. End Class
    Wenn ich es so mache, bekomm ich den Fehler:
    ​Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement LblAnzeige erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.


    Muss ich das irgendwie mit Delegates machen?

    Quellcode

    1. ​Option Strict On
    2. Imports System.Threading
    3. Public Class Main
    4. Event EsIstWasPassiert()
    5. Public daten As Integer
    6. Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    7. Dim Subthread1 As New Threading.Thread(AddressOf Endlosschleife)
    8. Subthread1.Start()
    9. End Sub
    10. Private Sub Endlosschleife()
    11. Do
    12. Thread.Sleep(100)
    13. '...
    14. daten = 5 'daten wurden hier aktualisiert
    15. RaiseEvent EsIstWasPassiert()
    16. '...
    17. Loop
    18. End Sub
    19. Private Sub UpdateAnzeige()
    20. LblAnzeige.Text = daten.ToString
    21. End Sub
    22. Private Sub EsIstWasPassiertProzedur() Handles Me.EsIstWasPassiert
    23. UpdateAnzeige()
    24. End Sub
    25. End Class
    Und da geht kein .NET 4.5? Ginge sogar über 4.0 mit Microsoft Async via NuGet.
    Ist ja weniger ein Sprachfeature, sondern Framework-Feature. Von daher sollte das schon gehen.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Danke für eure Hilfe, habe es jetzt so gelöst.

    Quellcode

    1. ​Option Strict On
    2. Imports System.Threading
    3. Public Class Main
    4. Public daten As Integer
    5. Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    6. Dim Subthread1 As New Threading.Thread(AddressOf Endlosschleife)
    7. Subthread1.Start()
    8. End Sub
    9. Private Sub Endlosschleife()
    10. Do
    11. Thread.Sleep(100)
    12. '...
    13. daten = 5 'daten wurden hier aktualisiert
    14. AccessControl()
    15. Loop
    16. End Sub
    17. Private Sub AccessControl()
    18. If Me.InvokeRequired Then
    19. Me.Invoke(New MethodInvoker(AddressOf AccessControl))
    20. Else
    21. LblAnzeige.Text = daten.ToString
    22. End If
    23. End Sub
    24. End Class
    Uih - ja, da hab ich wieder zu kompliziert gedacht.
    Aber trotzdem paar Sachen:
    • Forum-Tipp: Nutze den VB-Tag, der stellt VB-Code besser dar
    • Mir geht das InvokeRequired immer auf die Nerven - das muss man doch nicht abprüfen, sondern das weiß man doch im NebenThread.
      Also

      VB.NET-Quellcode

      1. Public Class Main
      2. Public daten As Integer
      3. Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      4. Dim Subthread1 As New Threading.Thread(AddressOf Endlosschleife)
      5. Subthread1.Start()
      6. End Sub
      7. Private Sub Endlosschleife()
      8. Do
      9. Thread.Sleep(100)
      10. '...
      11. daten = 5 'daten wurden hier aktualisiert
      12. Me.BeginInvoke(New MethodInvoker(AddressOf AccessControl))
      13. Loop
      14. End Sub
      15. Private Sub AccessControl()
      16. LblAnzeige.Text = daten.ToString
      17. End Sub
      18. End Class

    • Und gugge Controls Threadsicher machen

    trader08733 schrieb:

    VB.NET-Quellcode

    1. Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    2. Dim Subthread1 As New Threading.Thread(AddressOf Endlosschleife)
    3. Subthread1.Start()
    4. End Sub
    Pack mal die Thread-Instanz aus der Prozedur in die Klasse:

    VB.NET-Quellcode

    1. Private Subthread1 As Threading.Thread
    2. Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    3. Subthread1 = New Threading.Thread(AddressOf Endlosschleife)
    4. Subthread1.Start()
    5. End Sub
    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!
    Hätte dazu nochmal eine Frage, wie rufe ich denn .BeginInvoke von einer anderen Klasse auf?
    Bekomme immer folgende Fehler:
    "Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde."
    Hab da wohl was nicht ganz verstanden.

    VB.NET-Quellcode

    1. ​Public Class Form1
    2. Private Subthread1 As Threading.Thread
    3. Dim clsSub As New Class1
    4. Public Sub AccessControl()
    5. LblAnzeige.Text = "bla"
    6. End Sub
    7. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    8. Subthread1 = New Threading.Thread(AddressOf clsSub.Endlosschleife)
    9. Subthread1.Start()
    10. End Sub
    11. End Class
    12. Public Class Class1
    13. Public Sub Endlosschleife()
    14. Do
    15. Thread.Sleep(100)
    16. '...
    17. 'daten wurden hier aktualisiert
    18. Form1.BeginInvoke(New MethodInvoker(AddressOf Form1.AccessControl))
    19. Loop
    20. End Sub
    21. End Class
    Jo von einer nicht-Gui-Klasse geht das nicht, bzw. nur mit Gewürge oder Hacks.
    Von einer nicht-Gui-Klasse wäre sauber, mit einem Progress(Of T)-Objekt zu arbeiten.

    Und sowas:

    VB.NET-Quellcode

    1. Form1.BeginInvoke()
    gewöhn dir bitte sofort ab für immer.
    Form1 ist kein Objekt, sondern ist ein Datentyp. Datentypen haben aber keine Methoden, sondern Datentypen sind einzig dazu nütze, Variablen zu deklarieren und mit dem Schlüsselwort New neue Objekte zu erstellen. Objekte haben Methoden.
    Vb schmuddelt da herum, und das ist katastrophal, denn dadurch werden Vb-Programmierer verdummt, dahingehend, dass sie einen Datentyp nicht mehr von einem Objekt unterscheiden können.
    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!