Fehler in einem Thread

  • VB.NET

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von OneWorld.

    Fehler in einem Thread

    Guten Abend alle zusammen,

    Ich habe ein Problem mit einem Thread. Undzwar kurz und knapp :



    In einer anderen Anwendung habe ich den Sub auch in einem anderen Thread laufen und funktioniert ohne Probleme nur hier nicht in einer eigenen Klasse : / . Könnte das an der eigenen Klasse liegen ?

    Gruß OneWorld
    Youtube Info Library 2013 jetzt im Showroom.
    Form1.Bla.Text funktioniert nicht.
    Eine Form muss über ihre Instanz, nicht aber über ihren Namen angesprochen werden.
    Leider lässt VB.NET dies wegen VB6-Kompatibilität zu. Unter C# hättest Du das gar nicht kompilieren können.
    Übergib dem Thread die Instahz mit Me und speichere sie Dir in einer Variable vom Typ Form1.
    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 schrieb:

    Übergib dem Thread die Instahz mit Me und speichere sie Dir in einer Variable vom Typ Form1.


    wie mache ich das am einfachsten ?
    Youtube Info Library 2013 jetzt im Showroom.

    OneWorld schrieb:

    wie mache ich das am einfachsten ?
    So:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Public Class Form1
    3. Private t As Thread
    4. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    5. t = New Thread(AddressOf ThreadProc)
    6. t.Start(Me)
    7. End Sub
    8. Private Sub ThreadProc(param As Object)
    9. Dim dlg As Form1 = Nothing
    10. If TypeOf (param) Is Form1 Then
    11. dlg = DirectCast(param, Form1)
    12. End If
    13. If dlg IsNot Nothing Then
    14. dlg.Invoke(Sub() dlg.Label1.Text = "bla")
    15. End If
    16. End Sub
    17. End Class

    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!
    Dein Thread aus dem du den Aufruf machst ist kein STA Thread.
    Das Problem dabei ist, dass STA Threads nur einmal pro Prozess laufen können. Der Rest sind dann MTA Threads. Deine GUI's verlangen aber einen STA Thread, da die Com-Schnittstellen darauf ausgelegt sind. Was du daher tun musst ist, mit Invoke arbeiten.

    Schau dir mal Control.Invoke an.

    Außerdem das Argument von RodFromGermany hat immernoch gültigkeit. Form1.* ist schlicht und einfach crap.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    thefiloe schrieb:

    Dein Thread aus dem du den Aufruf machst ist kein STA Thread.
    Zum Glück.
    In einem STA Thread werden z.B. .NET-Programme gestartet.
    Diesen hier kannst Du 17 Mal und öfter starten, wenn Du Lust hast.
    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!

    OneWorld schrieb:

    werd ich mir mal anschaun
    Sieh Dir mal mein Beispiel an. ;)
    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!
    oh sry ich hab das Plus übersehen :D

    [edit]: Ich hab daas jetzt so gemacht :

    VB.NET-Quellcode

    1. Private Sub OrtungsDienst(ByVal param As Object)
    2. Dim dlg As Form1 = Nothing
    3. If TypeOf (param) Is Form1 Then
    4. dlg = DirectCast(param, Form1)
    5. End If
    6. If dlg IsNot Nothing Then
    7. If dlg.TextBoxServerdomain.Text = "" Then
    8. IsNothing(True)
    9. Else
    10. Dim txtCity As New TextBox
    11. Dim IPCity As String = GeoInformation.Online.GetIPFromAddress(dlg.TextBoxServerdomain.Text)
    12. Dim CityGoogle As String = GeoInformation.Online.GetCity(IPCity)
    13. dlg.Invoke(Sub(City As String)
    14. If IsNothing(Me) Then Exit Sub
    15. MsgBox("Der Server steht in " & GeoInformation.Online.GetCity(City), MsgBoxStyle.Information)
    16. Try
    17. Dim queryAddress As New StringBuilder()
    18. queryAddress.Append("http://maps.google.com/maps?q=")
    19. txtCity.Text = (GeoInformation.Online.GetCity(City))
    20. If txtCity.Text <> String.Empty Then
    21. City = txtCity.Text.Replace(" ", "+")
    22. queryAddress.Append(City + "," & "+")
    23. End If
    24. dlg.WebBrowser1.Navigate(queryAddress.ToString())
    25. Catch ex As Exception
    26. MessageBox.Show(ex.Message.ToString(), "Unable to Retrieve Map")
    27. End Try
    28. End Sub, _
    29. New Object() {IPCity})
    30. End If
    31. End If
    32. End Sub


    Nur der Inhalt des Subs geht jetzt nicht mehr obwohl nichts verändert wurde :?:
    Youtube Info Library 2013 jetzt im Showroom.

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

    Hi
    wenn nicht auf das Resultat gewartet werden soll, kannst du auch BeginInvoke verwenden. In deinem Fall ist es übrigens äußerst empfehlenswert den Programmteil von der Gui loszulösen. Statt die gesamte Aktion in einen anderen Thread auszulagern, führe einfach nur die Evaluation in einem anderen Thread aus und übergib dann einen String o.Ä. per BeginInvoke als Resultat zurück.
    Ich denk' mal, dass das eine Message ist. Bei Gui-Anwendungen arbeitet ein Thread die Nachrichtenschleife ab. Somit wird bei Invoke/BeginInvoke ein Delegat (bzw. Zeiger) in die Nachrichtenschleife eingereiht und später aufgerufen. Zusätzlich würde bei Invoke eben unnötig auf die Ausführung gewartet und das kann dauern, da eben MouseDown, KeyDown, etc. und abonnierende event handler ebenfalls auf diesem Thread und darin oftmals lang andauernde Operationen ausgeführt werden. Wenn es nicht notwendig ist, kannst du einfach BeginInvoke verwenden, da wird dann halt nicht gewartet.
    Statt extra einen Thread zu erzeugen, könntest du einfach einen Thread aus dem Anwendungs-thread pool verwenden, sofern dir das nicht zu komplex ist (siehe dazu System.Threading.ThreadPool).
    Invoke nimmt als 1. Parameter einen Delegaten und als 2. Parameter ein Array an Argumenten, die den Parametern des Delegaten entsprechen. Das Array ist allerdings zu behandeln, wie eine endlose Parameterliste, das ist das eigentlich das gleiche, wie New Object(){arg1, arg2, ...} (ParamArray sorgt dafür).

    Gruß
    ~blaze~
    uuh Danke für den Tipp. Ich müsste eigentlich zwei Werte zurückgeben einmal den Ort wo der Server steht und einmal den letzten Teil von dem googlemaps Link als String.
    Youtube Info Library 2013 jetzt im Showroom.
    Erzeuge einfach einen Delegaten mit 2 Parametern und übergib diesen an die Invoke-Funktion:

    VB.NET-Quellcode

    1. Public Delegate Sub Callback(ByVal serverLocation As String, ByVal googleMapsLink As String)

    Den Delegaten erzeugst du einfach per

    VB.NET-Quellcode

    1. Me.BeginInvoke(New Callback(Sub(p1, p2)
    2. MessageBox.Show(String.Concat(p1, vbCrLf, p2))
    3. End Sub), serverloc, maplink)

    (oder halt per AddressOf)

    Gruß
    ~blaze~
    ja ok das Problem bei mir ist, das ich noch am lernen bin und ich muss noch viel lernen :/ am besten schau ich mir erst mal das ganze an und komm dann nochmal drauf zurück
    Youtube Info Library 2013 jetzt im Showroom.

    ~blaze~ schrieb:

    Erzeuge einfach einen Delegaten mit 2 Parametern und übergib diesen an die Invoke-Funktion:

    Visual Basic Quellcode



    Public Delegate Sub Callback(ByVal serverLocation As String, ByVal googleMapsLink As String)


    Den Delegaten erzeugst du einfach per

    Visual Basic Quellcode

    Me.BeginInvoke(New Callback(Sub(p1, p2)
    MessageBox.Show(String.Concat(p1, vbCrLf, p2))
    End Sub), serverloc, maplink)


    (oder halt per AddressOf)


    Eigentlich alles :S
    Youtube Info Library 2013 jetzt im Showroom.
    Also was ein Delegat ist, weißt du, oder? Das kannst du dir als Stellvertreter vorstellen. Während du eine Methode direkt aufrufen kannst, kannst du eine Methode quasi in einen Delegaten stecken:

    VB.NET-Quellcode

    1. Public Sub X()
    2. MessageBox.Show("Hello World")
    3. End Sub
    4. Private Sub Form_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    5. X()
    6. End Sub

    So sieht ein normaler Methodenaufruf aus. Wenn jetzt X "dynamisch" sein soll, kannst du einen Delegaten verwenden:

    VB.NET-Quellcode

    1. Public Delegate Sub SomeDelegateType()
    2. Public Sub X()
    3. MessageBox.Show("Hello World")
    4. End Sub
    5. Public Sub Y()
    6. MessageBox.Show("Foo")
    7. End Sub
    8. Private Sub Form_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    9. Dim delegat As SomeDelegateType = AddressOf X 'Methode in Delegaten kapseln
    10. delegat.Invoke() 'Delegat aufrufen
    11. End Sub

    Im allgemeinen Sprachgebrauch gibt's das Wort Delegat übrigens auch. Das ist quasi einfach ein Stellvertreter.
    AddressOf erzeugt einen Delegaten von einer benannten Methode, während es halt auch die in den vorher aufgezeigten Beiträgen Variante mit dem Sub bzw. Function anstelle des AddressOf.
    Ich würde mal sagen, dass die Definition in diesem Fall einfach vernachlässigbar ist, solange dir klar ist, was du damit anfangen kannst.
    Wichtig ist nur:
    - Instanz des Delegaten erzeugen, das geht per New <Name>, wie bei jeder Instanz
    - Sinn eines Delegaten - ist halt quasi ein Verweis auf eine Methode
    - Die Methode und der Delegat müssen den gleichen Aufbau haben

    String.Concat arbeitet ählich, wie string1 & string2 & string3 und erfüllt den gleichen Zweck, nur performanter. Die Ausführungsreihenfolge wäre halt (string1 & string2) & string3. Damit würden string1 und string2 zusammengefügt und danach erst string3 drangehängt. String.Concat erledigt das in einem Rutsch.

    Gruß
    ~blaze~