Form aufrufen vom Delegate führt zum Freeze der Form

  • VB.NET
  • .NET (FX) 4.5–4.8

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

    Form aufrufen vom Delegate führt zum Freeze der Form

    Tachchen,

    Hab ein wired Problem wo ich ehrlich gesagt nicht dahinter steige wo das Problem liegt.

    Das Programm besteht aus zwei Teilen.

    Einem Launcher und einem Server zum Launcher. Der Server tut was er soll. Er bekommt einen LoginString wo alle Daten enthalten sind löst sie auf gleicht sie ab mit der Datenbank und schickt die Antwort zurück zum Client like "LOGIN:SUCCESS". Sobald der Client diese Nachricht erhält (die auch definitiv bei ihm ankommt) ruft er eine Funktion auf die das Loginfenster closed und den Launcher anzeigt. Es ist aber auch egal welche Form ich aufrufe der Fehler (Siehe Bild) ist immer der gleiche.

    Der Code ausschnitt

    VB.NET-Quellcode

    1. Private Sub Listen()
    2. While Client.Connected
    3. Try
    4. Dim MSGServer As String = StreamR.ReadLine
    5. If MSGServer = "LOGIN:SUCCESS" Then
    6. Dim msd As New DReceiveLoginMessage(AddressOf SuccessLogin)
    7. msd.Invoke()
    8. ElseIf MSGServer = "LOGIN:ERROR" Then
    9. Dim msd As New DReceiveLoginMessage(AddressOf ErrorLogin)
    10. msd.Invoke()
    11. End If
    12. Catch ex As Exception
    13. MsgBox("Die Verbindung zu den ####### Servern wurde verloren. Der Launcher wird jetzt beenden.")
    14. 'Application.Exit()
    15. End Try
    16. End While
    17. End Sub
    18. Private Sub ErrorLogin()
    19. MsgBox("Fehler bei der Anmeldung.")
    20. End Sub
    21. Private Sub SuccessLogin()
    22. Launcher_Form.Show()
    23. Login_Form.Close()
    24. End Sub


    Die Form freezt und schickt im Schacht. Nach beenden via der Debugsitzung kriegt der Server mit das der Client weg ist und Ende. Liegt das an den Delegates?
    Bilder
    • Ashampoo_Snap_Dienstag, 26. Juni 2018_14h13m07s_001_.png

      15,65 kB, 1.029×770, 98 mal angesehen
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de
    @Pascal Wo landet er, wenn Du während des Debuggens einfach mal Break machst?
    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!
    Er geht einmal alles durch. Zeigt die Form an und endet am Kommentar -> Siehe Kommentar im Code ;)

    VB.NET-Quellcode

    1. Private Sub Listen()
    2. While Client.Connected
    3. Try
    4. Dim MSGServer As String = StreamR.ReadLine '====> Genau hier bricht er und freezt. <====
    5. If MSGServer = "LOGIN:SUCCESS" Then
    6. Dim msd As New DReceiveLoginMessage(AddressOf SuccessLogin)
    7. msd.Invoke()
    8. ElseIf MSGServer = "LOGIN:ERROR" Then
    9. Dim msd As New DReceiveLoginMessage(AddressOf ErrorLogin)
    10. msd.Invoke()
    11. End If
    12. Catch ex As Exception
    13. MsgBox("Die Verbindung zu den ####### Servern wurde verloren. Der Launcher wird jetzt beenden.")
    14. 'Application.Exit()
    15. End Try
    16. End While
    17. End Sub
    18. Private Sub ErrorLogin()
    19. MsgBox("Fehler bei der Anmeldung.")
    20. End Sub
    21. Private Sub SuccessLogin()
    22. Launcher_Form.Show()
    23. Login_Form.Close()
    24. End Sub
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de
    @Pascal Wo genau kommt StreamR her?
    Es wäre doch vernünftiger, die Stream-Instanz innerhalb einer Prozedur zu kapseln.
    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!
    Das ganze ist eine Art Vermittlungsklasse die einen TCP Client bereitstellt und die Kommunikation zwischen Client und Server regelt.
    Der Server bekommt die Anfrage - Wertet diese aus und gibt dem Client dementsprechend eine Rückgabe. Das einzige Problem dabei ist sobald er die Rückmeldung bekommt vom Server und eine Form anzeigen soll friert der Client ein und hat keine Lust mehr.

    Der Anfang sieht in etwa so aus

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.Net
    3. Imports System.IO
    4. Imports System.Windows.Forms.Control
    5. Public Class TCP
    6. Public Stream As NetworkStream
    7. Public StreamW As StreamWriter
    8. Public StreamR As StreamReader
    9. Public Client As New TcpClient
    10. Private t As New Threading.Thread(AddressOf Listen)
    11. Private Delegate Sub DAddItem(ByVal s As String)
    12. Private Delegate Sub DSendChatMsg(ByVal msg As String)
    13. Private Delegate Sub DReceiveLoginMessage()
    14. Sub New(IPAddress As String, Port As Integer)
    15. Try
    16. Client.Connect(IPAddress, Port)
    17. If Client.Connected Then
    18. Stream = Client.GetStream
    19. StreamW = New StreamWriter(Stream)
    20. StreamR = New StreamReader(Stream)
    21. t.Start()
    22. Else
    23. MsgBox("Die #### Server sind derzeit nicht erreichbar.")
    24. Application.Exit()
    25. End If
    26. Catch ex As Exception
    27. MsgBox("Die #### Server sind derzeit nicht erreichbar.")
    28. Application.Exit()
    29. End Try
    30. End Sub


    EDIT: Ich geh davon aus das die TCP Klasse versucht die Form im eigenen Thread zu starten. Ich möchte die Form aber im Hauptthread haben. Gibts dazu ne möglichkeit oder müsste es ein weiteres Invoke sein?


    EDIT 2: Also... wenn ich die Form mit Form.Show aufrufe und danach direkt Application.Run() aufrufe funktionierts. So ganz versteh ich den Sinn dahinter nicht aber solang ich keine Atomrakete gezündet habe bin ich zufrieden. xD Melde mich wenns eigenartig sich verhält.
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de

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

    @Pascal Du hast einen Stream zum Lesen, einen zum Schreiben.
    Ich würde die bidirektionale Kommunikation über Socket betreiben:
    msdn.microsoft.com/de-de/library/aa964694(v=vs.85).aspx
    codeplanet.eu/tutorials/csharp…rammierung-in-csharp.html
    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!
    Das wäre für diese Applikation wohl ein wenig übertrieben. Da diese nur einen kleinen Zweck verfolgt. Rein theoretisch wäre es nur nötig die Form in den UI Thread(Mainthread) zu verlagern damit der Serverthread seinen Job weiter machen kann. Die Form hört auf zu laden da der Form.Load Befehl erst zu Ende geführt wird wenn der StreamR.ReadLine eine neue Nachricht erhält.

    Nun zur Frage: Eine Idee wie man die Form zurück in den Mainthread Invoked?
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de

    Pascal schrieb:

    wie man die Form zurück in den Mainthread Invoked?
    Gefühlte 10000 Treffer bei der Forums-Suche.

    VB.NET-Quellcode

    1. Private Sub InvokeLabelTextChange(txt As String)
    2. If (Me.InvokeRequired) Then
    3. Me.Invoke(New Action(Of String)(AddressOf InvokeLabelTextChange), txt)
    4. Return
    5. End If
    6. Me.Label1.Text = txt
    7. 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!
    Das Funktioniert nur wenn der Code innerhalb der Form steckt aber dieser ist ausgelagert in eine Klasse und sollte wenn möglich auch da bleiben.

    Innerhalb des Thread Me gegen Form Namen austauschen funktioniert so nicht und dafür such ich grad die Lösung. ;)
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de

    Pascal schrieb:

    Innerhalb des Thread Me gegen Form Namen austauschen funktioniert so nicht
    So isses, da erstellst Du Dir eine weitere Instanz der sch... mist ranz VB6-Kompatibilitätsform. Gugst Du Dialoge: Instanziierung von Forms und Aufruf von Dialogen
    Du brauchst den Zugriff auf eine GUI-Klasse!
    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!
    Das habe ich mir bereits durchgelesen. Aber hilft mir nicht bei meinem spezifischen Problem. Mir geht es darum eine Form aufzurufen die davor nie erstellt wird sondern erst dann instanziert wird wenn der Server es dem Client sagt.

    Innerhalb des Thread FormName.Show zu machen funktioniert so nicht. Mit einem Delegate funktioniert es nur stoppt er bei der Ausführung wegen dem StreamReader da dieser erst weiter Arbeitet wenn dieser eine neue Nachricht bekommt vom Server.

    Mein Ziel ist es jetzt eine Art Tür zurück zum Mainthread zu machen. Dieser soll auf den Befehl des Servers hin eine Form schließen und die andere öffnen. ;)

    Like: Mainthread zeigt eine Form -> Führt eine Aktivität aus -> Startet den Server -> Server wartet auf Nachricht -> Bekommt eine Aufgabe und übergibt diese dem Mainthread.

    Soweit funktioniert das. Bis auf die Tatsache das dass Aufrufen der Form ein Freeze zur Folge hat. Innerhalb des Delegates kann ich ein Form.Show machen und via Applikation.Run() diese tätsächlich aufrufen. Aber nur einmal. Ist die Form geschlossen passiert danach garnichts mehr.
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de
    Das wäre eine gewesen. Und ich weiß ich werde dafür auch gleich erschlagen aber letztendlich war die Lösung des Problems

    Ja das verwenden von OpenForms ist gemein. Aber für meinen Fall wo ich genau weiß was das Programm wann macht und es null abweichung geben kann es seiden jemand haut mitm Hammer auf den PC ein ist das Inordnung ;)
    Und wie man mehrmals sagte ich brauch ein Fensterhandle ;)

    VB.NET-Quellcode

    1. Dim invokeForm As Form = Application.OpenForms("login_form") 'Zum Zeitpunkt ist diese Form DEFINITIV immer offen.
    2. If invokeForm.InvokeRequired Then
    3. invokeForm.BeginInvoke(Sub()
    4. 'Login_Form.Close()
    5. Launcher_Form.Show()
    6. End Sub)
    7. End If
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de
    Ich will ja den Tasmanischen Teufel nicht an die Wand skizzieren, aber wenn ich Invoke in Kombination mit Launcher_Form.Show() sehe, wende ich nur ein, dass das komisch enden kann.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Das ist Richtig aber in diesem Fall gibt es nur diese eine Form die ge"showt" wird. Sobald diese angezeigt wird gibt es keine weiteren formen mehr.
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de
    @Pascal Ich würde ein Event an das Parent senden (muss keine Form-Klasse sein, und falls nicht, sendet die wieder ein Event an ihr Parent, bis eine Form-Klasse erereicht ist), die Form kann dann ordentlich invoken.
    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!
    Wieso sollte OpenForms("login_form") nicht ordentlich invoken können??

    Ich würde es allerdings noch vereinfachen (und sicherer):

    VB.NET-Quellcode

    1. Dim invokeForm As Form = Application.OpenForms(0) 'Zu ungefähr **jedem** Zeitpunkt ist **irgendein** Form DEFINITIV immer offen.
    2. ' Bzw Fälle, wo diese Vorgehensweise scheitert, müssen sehr aussergewöhnlich sein


    Und wieso findet der TE "das verwenden von OpenForms ist gemein."?
    Persönlich ist das rein eine Annahme aus Erfahrungswerten anderer Entwickler die mir von eigenartigen Problemen erzählt haben bei der Verwendung von OpenForms. Ich kann dazu leider nur sagen - hatte damit noch nie Probleme

    (Falls interessiert: Probleme waren so Dinge wie unvorhersehbaren Crashes oder das Programm hat sich an diesen Punkt aufgehangen ohne ersichtliche Gründe.)

    Und @ErfinderDesRades stimmt. So isses kürzer und defintiv safer.

    //Can be closed :)
    "Es gibt guten und schlechten Code und es gibt Code der einfach nur Funktionieren soll." - P. White


    www.pacrafts.de
    @Pascal Ich verwende auch OpenForms und hatte noch nie Probleme damit.
    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!