Threads

  • VB.NET
  • .NET (FX) 4.0

Es gibt 40 Antworten in diesem Thema. Der letzte Beitrag () ist von EaranMaleasi.

    Guten Morgen allerseitz,

    ich habe den Code hier von Microsoft Kopiert um mich mal mit Threads zu befassen, aber ich bekomme eine InvalidOperationException

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Public Class frmThreads
    3. '*** Globale Variable ***
    4. Private trd As Thread
    5. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    6. MessageBox.Show("Main Thread")
    7. End Sub
    8. '*** Methode ***
    9. Private Sub ThreadTask()
    10. Dim stp As Integer
    11. Dim newval As Integer
    12. Dim rnd As New Random()
    13. Do
    14. stp = ProgressBar1.Step * rnd.Next(-1, 2)
    15. newval = ProgressBar1.Value + stp
    16. If newval > ProgressBar1.Maximum Then
    17. newval = ProgressBar1.Maximum
    18. ElseIf newval < ProgressBar1.Minimum Then
    19. newval = ProgressBar1.Minimum
    20. End If
    21. ProgressBar1.Value = newval
    22. Thread.Sleep(100)
    23. Loop
    24. End Sub
    25. Private Sub frmThreads_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    26. trd = New Thread(AddressOf ThreadTask)
    27. trd.IsBackground = True
    28. trd.Start()
    29. End Sub
    30. End Class
    Bilder
    • 1.JPG

      24,91 kB, 411×150, 171 mal angesehen
    Hallo

    Die Fehlermeldung sagt dir ja alles was du wissen musst. Du kannst von einem Nebenthread nicht auf Control (welche im UI Thread laufen) zugreifen.
    Du musst sie invoken.

    Die meisten control bieten auch ein Invoke an.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    also in etwa so, (auch kopiert) aber ich verstehe :)

    danke
    Spoiler anzeigen

    VB.NET-Quellcode

    1. If Me.ProgressBar1.InvokeRequired Then
    2. Dim d As New SetTextCallback(AddressOf ThreadTask)
    3. Me.Invoke(d, New Object() {[Text]})
    4. Else
    5. ProgressBar1.Value = newval
    6. End If
    Hallo

    Ich mach fast nie winForms, musste es selbst mal schnell probieren.

    Das hier habe ich jetzt mal schnell erzeugt:

    VB.NET-Quellcode

    1. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    2. Dim tr As New Threading.Thread(AddressOf Test)
    3. tr.IsBackground = True
    4. tr.Priority = Threading.ThreadPriority.Lowest
    5. tr.Start()
    6. End Sub
    7. Private Sub Test()
    8. For i As Integer = 0 To 9
    9. Dim index As Integer = i
    10. If Me.ListBox1.InvokeRequired Then
    11. Me.ListBox1.Invoke(Sub() Me.ListBox1.Items.Add("Test " & index.ToString))
    12. Else
    13. Me.ListBox1.Items.Add("Test " & index.ToString)
    14. End If
    15. Threading.Thread.Sleep(200)
    16. Next
    17. End Sub



    Edit: Solltest du auf 4.5 umstellen können hättest du Async/Await zur Verfügung 8o

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Verständliches Beispiel, danke ^

    Kann ich innerhalb einer schon bestehenden Methode einen Thread verwenden?

    Weil ich hab eine kleine anwendung die pdf´s an ei nen Drucker sendet, das "Senden" ereignis in ein Thread packen und die ProgressBar an den Thread binden, so hätte ich es zumindest gerne

    so das wäre das eine :)
    Wie kann ich nun eine ProgressBar an den Tatsächlichen vortschritt des Prozesses hängen?


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub test()
    2. For Each zeile As String In Me.ListBox1.Items
    3. Try
    4. If Me.ListBox1.InvokeRequired Then
    5. Me.ListBox1.Invoke(Sub() Me.s.SendFile(zeile))
    6. '** Textfeld nach abschiocken an den Drucker wieder leeren ***
    7. ListBox1.Items.Clear()
    8. End If
    9. Catch ex As Exception
    10. End Try
    11. Next
    12. End Sub

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

    Blackn0va schrieb:

    das "Senden" ereignis in ein Thread packen und die ProgressBar an den Thread binden, so hätte ich es zumindest gerne


    Verstehe nicht ganz dein Vorhaben. Versuchs mal und schau was passiert und dann gehen wir es durch.

    PS: Wenn du nachträglich was Editierst und da ist ne frage enthalten solltest du jemanden markieren, hab nur durch zufall nochmal hier reingesehen.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    @Blackn0va Geschickter ist es, das InvokeRequired außerhalb der Schleife abzufragen, da das natürlich für alle Elemente und damit auch für die Form selbst gilt:

    VB.NET-Quellcode

    1. Private Sub Test()
    2. If Me.InvokeRequired Then
    3. Me.Invoke(Sub() Me.Test())
    4. ' Ruft sich selbst auf, deswegen das Return
    5. Return
    6. End If
    7. For Each zeile As String In Me.ListBox1.Items
    8. Try
    9. Me.s.SendFile(zeile)
    10. '** Textfeld nach abschicken an den Drucker wieder leeren ***
    11. 'ListBox1.Items.Clear() ' was soll das nier?
    12. Catch ex As Exception
    13. End Try
    14. Next
    15. 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!

    ErfinderDesRades schrieb:

    Noch geschickter wäre es, Async/Await sein Job machen zu lassen:

    Aber hald erst aber .Net 4.5 und VS 2012. Er proggt ja leider unter 4.0. Habe ich eh auch empfohlen ;)

    Grüßle
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    RodFromGermany schrieb:

    @Blackn0va Geschickter ist es, das InvokeRequired außerhalb der Schleife abzufragen, da das natürlich für alle Elemente und damit auch für die Form selbst gilt:

    VB.NET-Quellcode

    1. Private Sub Test()
    2. If Me.InvokeRequired Then
    3. Me.Invoke(Sub() Me.Test())
    4. ' Ruft sich selbst auf, deswegen das Return
    5. Return
    6. End If
    7. For Each zeile As String In Me.ListBox1.Items
    8. Try
    9. Me.s.SendFile(zeile)
    10. '** Textfeld nach abschicken an den Drucker wieder leeren ***
    11. 'ListBox1.Items.Clear() ' was soll das nier?
    12. Catch ex As Exception
    13. End Try
    14. Next
    15. End Sub


    Deine Frage "was das hier soll ^"
    nach dem senden an den Drucker soll die ListBox wieder geleert werden. Ich habe nun versucht, einen der 3 Drucker in einen Thread zu überführen, leider ohne erfolg, da der Drucker nichts mehr bekommt, aber ich auch keinen Laufzeitfehler..

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub DruckerHPF()
    2. If Me.InvokeRequired Then
    3. Me.Invoke(Sub() Me.DruckerHPF())
    4. If s.Connected = False Then
    5. s.Close()
    6. Return
    7. End If
    8. '*** HPF Backoffice ***
    9. s.Connect("IP VOM DRUCKER", 9100)
    10. '*** Timer für die prgBar starten ***
    11. Timer1.Start()
    12. '*** Für jede Zeile in der ListBox wird ein String an den Drucker gesendeT ***
    13. For Each zeile As String In ListBox1.Items
    14. '*** Senden e ines Srings an den Drucker ****
    15. s.SendFile(zeile)
    16. ListBox1.Items.Clear()
    17. Next
    18. End If
    19. End Sub


    den aufruf versuche ich so.. index 0 ignorieren, also nichts unternehmen, index 3 ist der Drucker im Thread
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ElseIf cboDrucker.SelectedIndex = 3 Then
    2. If s.Connected = False Then
    3. s.Close()
    4. Return
    5. End If
    6. '*** Thread Drucker3 Asuführen ***
    7. Dim tr As New Threading.Thread(AddressOf DruckerHPF)
    8. tr.IsBackground = True
    9. tr.Priority = Threading.ThreadPriority.Normal
    10. tr.Start()
    11. End If


    @Nofear23m also jetzt sendet er schonmaol an den Drucker, allerdings wenn ich das programm nach einem Druck nicht beende und noch ein dokument senden möchte, bekomme ich einen Ausnahmefehler, im rechten bild zu sehen.

    VB.NET-Quellcode

    1. if s.connected = false then
    2. s.connect = true
    3. end if
    ?
    Bilder
    • 1.JPG

      32,59 kB, 595×491, 181 mal angesehen
    • 1.JPG

      45,49 kB, 698×408, 155 mal angesehen

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

    Spoiler anzeigen

    VB.NET-Quellcode

    1. '*** HPF Backoffice ***
    2. Private Sub DruckerHPF()
    3. If Me.InvokeRequired Then
    4. Me.Invoke(Sub() Me.DruckerHPF())
    5. End If
    6. '** Deklaration eines Druckers im Lokalem netzwerk ***
    7. Dim s As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    8. '*** Wenn verbindung aktiv, dann Trennen ***
    9. If s.Connected = True Then
    10. '*** Trennen ***
    11. s.Disconnect(True)
    12. '*** Verbindung Trennen ***
    13. s.Close()
    14. End If
    15. s.Connect("IP VOM DRUCKER", 9100)
    16. For Each zeile As String In Me.ListBox1.Items
    17. '*** Senden e ines Srings an den Drucker ****
    18. s.SendFile(zeile)
    19. tr2.Start()
    20. Next
    21. End Sub


    Was ist daran falsch?

    Also so bekommt der Drucker schonmal wieder was zugeschickt, aber wenn nur eine PDF in der ListBox ist mit einer leeren Seite, Druckt der Drucker jeweils 3 Seiten aus

    Spoiler anzeigen

    VB.NET-Quellcode

    1. '*** HPF Backoffice ***
    2. Private Sub DruckerHPF()
    3. If Me.InvokeRequired Then
    4. Me.Invoke(Sub() Me.DruckerHPF())
    5. End If
    6. '** Deklaration eines Druckers im Lokalem netzwerk ***
    7. Dim s As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    8. If Me.ListBox1.InvokeRequired Then
    9. Me.ListBox1.Invoke(Sub() Me.DruckerHPF())
    10. End If
    11. For Each zeile As String In Me.ListBox1.Items
    12. s.Connect("IP VON DRUCKER", 9100)
    13. '*** Senden e ines Srings an den Drucker ****
    14. s.SendFile(zeile)
    15. Next
    16. s.Close()
    17. Return
    18. End Sub


    Ich hab noch eine Frage, muss ich jedes Steuerelement, jede Prozedur oder Methode für einen Thread Invoken?
    Wenn ja, kann ich das in einen Thread packen, z.B einen Timer, die ProgressBar und die Listbox, oder sollte ich dazu dann jeweils einen Thread erstellen?

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

    Weil das return fehlt?

    Ich will das ja verstehen, weil es eine sehr nützliche sache ist.
    Wie würdest du das denn machen @ErfinderDesRades?

    Wäre es also vom verständlis besser einen Thread in einer Extra klasse zu Definieren oder wie kann ich das Verstehen mit dem selbst Invoken?

    Blackn0va schrieb:

    Weil das return fehlt?
    Klar.
    Die Sub ruft sich selbst noch einmal aus einem anderen Thread auf, das wird dann bei If Me.InvokeRequired Then übersprungen.
    Du führst also diese Sub einmal im GUI- und einmal im aufrufenden Thead aus, sofern dieser Aufruf aus einem anderen Thread kommt.

    Blackn0va schrieb:

    Deine Frage "was das hier soll ^"
    Du machst eine Schleife über alle Items, löschst aber nach der Bearbeitung des 1. Items alle Items, die können dann, so vorhanden, nicht mehr abgearbeitet werden.
    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!
    @RodFromGermany und weil alles in der schleife ist, ist

    VB.NET-Quellcode

    1. ListBox1.Items.Clear()


    vöölig unnötig weil er die listbox bei jedem durchlaf erneut leert.. Verstehe
    Also so in die richtung

    Spoiler anzeigen

    VB.NET-Quellcode

    1. '*** HPF Backoffice ***
    2. Private Sub DruckerHPF()
    3. If Me.InvokeRequired Then
    4. Me.Invoke(Sub() Me.DruckerHPF())
    5. return
    6. End If
    7. '** Deklaration eines Druckers im Lokalem netzwerk ***
    8. Dim s As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    9. If Me.ListBox1.InvokeRequired Then
    10. Me.ListBox1.Invoke(Sub() Me.DruckerHPF())
    11. return
    12. End If
    13. For Each zeile As String In Me.ListBox1.Items
    14. s.Connect("IP VOM DRUCKER", 9100)
    15. '*** Senden e ines Srings an den Drucker ****
    16. s.SendFile(zeile)
    17. Next
    18. s.Close()
    19. Return
    20. End Sub

    (War eben der Falsche Code sorry!)


    Da bekommt der Drucker anstatt 1 Blatt, 3 Blätter geschickt?

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „Blackn0va“ () aus folgendem Grund: 80 mal bearbeiten ist das ziel...

    Blackn0va schrieb:

    3 Blätter geschickt?
    Weiß ich nicht, da ich diesen Drucker und diese Druckprozedur nicht kenne.
    Sieh Dir mal dies an:

    VB.NET-Quellcode

    1. '*** HPF Backoffice ***
    2. Private Sub DruckerHPF()
    3. If Me.InvokeRequired Then
    4. Me.Invoke(Sub() Me.DruckerHPF())
    5. Return
    6. End If
    7. '** Deklaration eines Druckers im Lokalem netzwerk ***
    8. Using s As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    9. For Each zeile As String In Me.ListBox1.Items
    10. s.Connect("IP VOM DRUCKER", 9100)
    11. '*** Senden e ines Srings an den Drucker ****
    12. s.SendFile(zeile)
    13. Next
    14. End Using
    15. 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!
    Danke @RodFromGermany das funktioniert gut.

    Kann ich bei zeile 12, also bei

    VB.NET-Quellcode

    1. s.SendFile(zeile)


    noch irgendwie die ProgressBar an einem ProgressChange Event hängen? Weiil noch starte ich dann einfach einen Timer der die ProgressBar füllt?

    Blackn0va schrieb:

    VB.NET-Quellcode

    1. Private Sub ThreadTask()
    2. ' ...
    3. ProgressBar1.Value = newval

    Ich denke mal, dies ist der Übeltäter für den Thread-übergreifenden Vorgang.
    Gib Deiner Progressbar den .Style = ProgressBarStyle.Marquee und schmeiß alles raus, was in Deinem Programm mit Threads und Invoke zu tun hat.
    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!