Seltsames Verhalten / System.InvalidOperationException in System.Windows.Forms.dll

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

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

    Seltsames Verhalten / System.InvalidOperationException in System.Windows.Forms.dll

    Moin,
    ist vermutlich mal wieder der Uhrzeit geschuldet, ich komme aber gerade absolut nicht weiter. Mindestens 1 Form lässt sich in meinem Programm nicht mehr öffnen.
    Nach dem Aufruf der Form wird die Release-Version ohne Meldung abgeschossen, im Debug wird die Ausgabe mit der o.g. Exception geflutet. Gehe ich im Debug im Einzelschritt
    durch, wird die Form geöffnet ?(

    Habt ihr einen Anhaltspunkt, wo ich anfangen kann zu suchen? Verändert worden ist an der Form nix - ich hatte aber heute tatsächlich Probleme mit der Datenbank, sollte daran aber nicht liegen. Rest läuft wie es soll

    LG und gute Nacht ;)
    Bilder
    • Unbenannt1.png

      2,23 MB, 631×354, 99 mal angesehen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Wenn es dermaßen geflutet wird, könnte eine Endlosschleife vorliegen. Erstmal Backup machen. Dann den ganzen UserCode im Form auskommentieren. Falls das nicht reicht, wird wohl in der Form.Designer.VB irgendwo der Wurm drin sein. Auch dort schritt-/blockweise alles auskommentieren.
    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.

    Takafusa schrieb:

    Setz mal Haltepunkte beim debuggen in allen Try/Catches(im catch)

    Ich nutze kaum Try-Catch in meinem Projekt.

    ErfinderDesRades schrieb:

    So kriegst du auch die Exceptions (etwas informativer), die dann anschliessend gecatcht werden sollen.

    In dem Fall hab ich's aber benutzt, und er hängt sich mit dem Threading-Waitdialog auf - wurde hier schon diskutiert, es gibt aber noch keine saubere Lösung leider :(
    Jetzt hab ich wieder das Problem, dass sich der WaitDialog manchmal nicht schließt :(
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Also ich kann den von dir beschriebenen Fehler ohne weiteres reproduzieren.


    Lösen lässt sich das Problem in dem eben gefragt wird ob das FormHandle bereits erstellt wurde und nur wenn es erstellt wurde wird dir Form geschlossen.

    C#-Quellcode

    1. public void Dispose()
    2. {
    3. Stop();
    4. Thread.Sleep(100);
    5. form?.Invoke(new MethodInvoker(() => { form.Dispose(); }));
    6. }
    7. private void Stop()
    8. {
    9. if (form?.IsHandleCreated == true)
    10. form.Invoke(new MethodInvoker(() => { form.Close(); }));
    11. }

    Fakiz schrieb:

    Guck dir doch mal die Dispose Methode an


    Also die direkte Übersetzung nach vb.net ergibt nichts gutes, denn mit "Function" mault Intellisense direkt rum:

    VB.NET-Quellcode

    1. Public Sub Dispose()
    2. [Stop]()
    3. Thread.Sleep(100)
    4. form?.Invoke(New MethodInvoker(Function()
    5. form.Dispose()
    6. End Function))
    7. End Sub
    8. Private Sub [Stop]()
    9. If form?.IsHandleCreated = True Then form.Invoke(New MethodInvoker(Function()
    10. form.Close()
    11. End Function))
    12. End Sub


    Hab's dann wie folgt mal angepasst:

    VB.NET-Quellcode

    1. Public Sub Dispose() Implements IDisposable.Dispose
    2. stopThread()
    3. Thread.Sleep(100)
    4. _waitDlg?.Invoke(New MethodInvoker(Sub()
    5. _waitDlg.Dispose()
    6. End Sub))
    7. End Sub
    8. Private Sub stopThread()
    9. If _waitDlg?.IsHandleCreated Then _waitDlg.Invoke(New MethodInvoker(Sub()
    10. _waitDlg.Close()
    11. End Sub))
    12. End Sub


    Crasehd aber direkt wegen fehlendem Handle..
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    tragl schrieb:

    was passiert wenn das Handle noch nicht erstellt wurde? WaitDlg verbleibt ja dann offen, soll er aber nicht :(
    Es gibt auch ein HandleCreated-Event bzw. OnHandleCreated ist overridable.
    Wenn das Handle also nicht da ist, kann man das Event vlt. abonnieren, und darin tun was zu tun ist (äh - was nochmal? achja - disposen)
    na viel Glück!
    Mal anders gefragt. Der "Fehler" mit dem Offenbleiben des Dialogs kommt ja nur (reproduzierbar) wenn zuviele Aufrufe in zu kurzen Abständen gemacht wurden.
    Würden denn 100ms oder weniger reichen als Wartezeit bis das Handle erzeugt wurde? Dann könnte ich doch abfragen:

    - wurde das handle erzeugt
    dann invoke und disposen,
    sonst 100ms warten und dann invoke und disposen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Was meinst du denn mit:
    wenn zuviele Aufrufe in zu kurzen Abständen gemacht wurden


    Ansonsten machst du ja genau das, du rufst die ThreadingT.Dispose Methode auf diese ruft die StopThread Methode auf welche Prüft ob das Handle erstellt wurde. Wurde dieses Erstellt wird die Form geschlossen sonst 100 ms geartet und die Form.Dispose Methode aufgerufen.

    Du könntest versuchen die Form, bei Aufruf der ThreadingT.Dispose Methode, auf Visible=False zu setzen und die Wartezeit auf z.B. 1000 ms zu erhöhen.


    PS: Aber ErfinderDesRades hat ja den HandleCreated - Event in den Raum geworfen damit liese sich das ja lösen. Zu beachten wäre hier das du im EventHandler nebenläufig die Form schließen musst damit die CreateHandle Methode nach auslösen des Events zuerst verlassen werden kann. Sonst kommst du vom Regen in die Traufe.

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

    Fakiz schrieb:

    Was meinst du denn mit:


    ich meine in einem übertriebenen Beispiel sowas:

    VB.NET-Quellcode

    1. For i = 1 To 100
    2. Dim dlg As New dlgIsBusy(i.ToString, "Test")
    3. Using New Threading.WaitDlg(dlg)
    4. Threading.Thread.Sleep(1)
    5. End Using
    6. Next


    Den WaitDlg nutze ich als Betriebshure, er wird quasi überall genutzt, wo ich einen solchen WaitDlg für sinnvoll halte - und das muss an so vielen Stellen wie möglich sein, damit der User nicht denkt da hätte sich was
    aufgehangen und wird panisch..
    Es kann aber durch verschiedene Methodenaufrufe auch passieren, dass der kurz hintereinander erscheint und dann knallt's
    bzw. verbleibt der Dialog offen und mann muss die Anwendung schließen und neu öffnen damit der weg ist.

    Als Beispiel: wegen mir sollen 10 Excel-Files in eine DataTable importiert und verarbeitet werden. Es gibt sehr große Excel-Files, also macht ein WaitDlg u.U. schon Sinn. Was aber, wenn es 10 klitzekleine sind?
    Dann wird der WaitDlg innerhalb kürzester Zeit 10x aufgerufen...
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    Fakiz schrieb:

    PS: Aber ErfinderDesRades hat ja den HandleCreated - Event in den Raum geworfen damit liese sich das ja lösen.

    Kannst du hier einen Ansatz geben? Ich steh' grad aufm Schlauch und weiß nicht, was ich mit dem Event soll, wenn ich doch IsHandleCreated abfragen kann?
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    In etwa so:
    Spoiler anzeigen

    C#-Quellcode

    1. private void StopThread() {
    2. if (_waitDlg?.IsHandleCreated)
    3. _waitDlg.Invoke(new MethodInvoker(() => { _waitDlg.Close() }));
    4. else
    5. _waitDlg.HandleCreated += (s,e) => { Task.Factory.StartNew(() => { Thread.Sleep(250); Dispose(); });}
    6. }



    Wobei ich dir davon abraten würde, wenn du die Form so oft brauchst solltest du sie nur einmal Instnzieren und dann mit Show/Hide arbeiten.
    @Fakiz
    Ich geh mal von einem Übersetzungsfehler aus:

    VB.NET-Quellcode

    1. If _waitDlg?.IsHandleCreated Then
    2. _waitDlg.Invoke(New MethodInvoker(Function()
    3. _waitDlg.Close()
    4. End Function))
    5. Else
    6. _waitDlg.HandleCreated += Function(s, e)
    7. Task.Factory.StartNew(Function()
    8. Thread.Sleep(250)
    9. Dispose()
    10. End Function)
    11. End Function
    12. End If


    Erste If-Anweisung hab ich wie folgt: _waitDlg.Invoke(New MethodInvoker(AddressOf _waitDlg.Close))
    Der Rest ergibt keinen Sinn:



    ist vielleicht auch noch eine Nummer zu hoch für mich...es muss doch eine einfache Möglichkeit geben, das sch.. Fenster dicht zu machen..
    Witzigerweise kann ich das Teil nicht mal Hiden, dann im Catch meckert er dann wieder über Threadübergreifenden Vorgang. Das soll mal jemand kapieren...

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Hi, da ich leider noch immer teilweise damit zu kämpfen habe, dass der BusyDialog teilweise geöffnet bleibt, obwohl er weg sein müsste
    und ich es nicht verstehe, wie ich das gelöst bekomme:

    Hätte hier jemand eine funktionierende Vorlage für mich? Oder kann mich Schritt für Schritt anleiten?
    Mit dem HandleCreated-Eventhandler aus Post 14 komm ich nicht zurecht, und verstehe auch nicht warum ich den brauchen
    sollte wenn ich .IsHandleCreated abfragen kann. Aber selbst damit funzt das ja nicht sauber :(

    Edit:
    Oder hab' ich hier schon die angesprochene Lösung jetzt gefunden? (Zeile2)

    VB.NET-Quellcode

    1. Public Sub Dispose() Implements IDisposable.Dispose
    2. If Not _waitDlg.IsHandleCreated Then Thread.Sleep(250)
    3. _waitDlg.Invoke(New MethodInvoker(AddressOf stopThread))
    4. 'Try 'Workaround. Crasht wg. fehlendem FensterHandle, wenn der WaitDlg schneller geschlossen wird, als das Handle erzeugt wurde.
    5. ' _waitDlg.Invoke(New MethodInvoker(AddressOf stopThread))
    6. 'Catch ex As InvalidOperationException
    7. ' '_waitDlg.Hide()
    8. 'End Try
    9. End Sub
    10. Private Sub stopThread()
    11. _waitDlg.Close()
    12. End Sub


    bei dem folgenden sehr übertriebenen Beispiel sieht man den BusyDialog flackern, ab und an ist er etwas länger zu sehen (vermutlich die 250ms vom Threading.Sleep) und es kommt kein Absturz mehr:

    VB.NET-Quellcode

    1. Private Sub RunTestSub(sender As Object, e As EventArgs) Handles tsRunTestSub.Click
    2. For i = 1 To 400
    3. Dim dlg As New dlgIsBusy(i.ToString, "Test")
    4. Using New Threading.WaitDlg(dlg)
    5. Threading.Thread.Sleep(1)
    6. End Using
    7. Next
    8. msgInformation("fertig")
    9. End Sub

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    Ich nochmal.. hat jetzt eine Zeit lang funktioniert, bis ich auf ein neues Problem gestoßen bin.
    Und zwar arbeite ich mit MDI (Parent/Child-Forms) und hab eigentlich immer im Form_Load-Event der Childs meine Daten aus der Datenbank geholt.
    Dauert u.U. zwar länger, bis das Childform angezeigt wird -sieht für den User aber nicht so unschön aus, wenn die Controls so halb dargestellt werden bis die
    Daten aus der DB dann geladen sind.

    Ich hab mir dann für's Laden der Daten aus der Datenbank auch den BusyDialog zur Hand genommen:

    VB.NET-Quellcode

    1. Public Sub TableFill(ParamArray tbls As DataTable())
    2. If App.PersistanceModeXml Then Return
    3. 'Await Tasks.Task.Run(Sub() tbls.ForEach(Sub(tbl) tbl.TablePersist.Fill())) 'TODO: Knallt im ExecuteFill??
    4. Dim dlg As New dlgIsBusy("Daten werden aus Datenbank geholt...", "")
    5. Using New WaitDlg(dlg)
    6. For Each tbl In tbls
    7. dlg.UpdateDescription($"{tbl.TableName}")
    8. tbl.TablePersist.Fill()
    9. Next
    10. End Using
    11. End Sub


    Damit bleibt mein Programm aber in einem Endlos-Loop hängen, weil im Form_Load das Child noch nicht da ist und er scheinbar? kein Handle erstellen kann.
    Ich musste also alles ins Form_Shown-Event packen, damit ging's dann - sieht aber nicht so schön aus.

    Falls ich irgendwo im Code was vergessen haben sollte zu ändern hab ich mir nen Workaround mit einer Stopwatch gebaut -> dann gibt's eine Exception, anstatt einem Endlos-Loop.
    Sieht aber irgendwie sehr unschön aus. Gibt's hier eine saubere endgültige Lösung für mein Problem? Wenn die Zeit abgelaufen ist, den BusyDialog einfach so ohne Invoke killen geht auch nicht,
    weil er im HandleCreating ist...

    VB.NET-Quellcode

    1. Public Sub Dispose() Implements IDisposable.Dispose
    2. Dim sw As New Stopwatch
    3. sw.Start()
    4. If Not _waitDlg.IsHandleCreated Then
    5. Do Until _waitDlg.IsHandleCreated
    6. If sw.ElapsedMilliseconds > 5000 Then Throw New Exception("FensterHandle konnte nicht erstellt werden!")
    7. Loop
    8. 'Thread.Sleep(250)
    9. End If
    10. sw.stop
    11. _waitDlg.Invoke(New MethodInvoker(AddressOf stopThread))
    12. End Sub
    13. Private Sub stopThread()
    14. _waitDlg.Close()
    15. End Sub

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Hi,
    du könntest auch in die "For Each tbl In tbls" - Schleife ein Application.DoEvents() reinmachen, dass deine deine restliche Fensterwelt nicht erinfriert.
    Wie sieht denn der Aufruf dieses MDI-Child-Fensters aus ... normalerweise kann man ja nach dem Instanziieren und vor den Show die Daten einfüllen ... da leben dann auch die Controls schon und man kann hier das meiste schon übergeben und vorbereiten.
    Den WaitDialog kannst du ja vorher Anzeigen und dann nach dem Ladevorgang wieder schließen.
    Und wenn man dann DoEvents an diversen langsamen Stellen einbaut, wird auch alles angezeigt.
    Oder hab ich hier ein Denk oder Verständnisproblem in dieser Sache?
    Liebe Grüße
    Hab's grad mal probiert...
    Im Konstruktor (Public Sub New() der Form scheint's ohne Probleme zu klappen. Dann sind auch noch keine Controls sichtbar, also die
    perfekte Lösung für mich ;)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: