Zugriffe auf Controls von einem anderen Thread teilweise nur per Invoke, teilweise aber auch ohne möglich.

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

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Zugriffe auf Controls von einem anderen Thread teilweise nur per Invoke, teilweise aber auch ohne möglich.

    Hallo, merkwürdiger Effekt, aber evtl. ist das OK.

    Ich habe einen Thread (grau) der erstellt eine ComboBox, eine TextBox, eine CheckBox, ein Label und einen 2ten Thread.
    Vom 2ten Thread (rot) lese ich die TextBox.Text und die CheckBox.Checked Eigenschaften aus Thread 1 interessanter Weise OHNE Invoke (grüner Pfeile).
    Den ComboBox.SelectedIndex lesen und die Label.Text Eigenschaft schreiben klappt nur mittel Invoke (rote Pfeile).
    Alle Zugriffe erfolgen per DirectCast.
    Gibt es dafür eine Erklärung?

    roepke schrieb:

    Gibt es dafür eine Erklärung?
    Sowohl der 1. (1te, erste) als auch der 2. (2te, zweite) Thread sind offensichtlich NICHT GUI-Thead.
    Da geht das Lesen halt direkt.
    Mit DirectCast hat das nix zu tun.
    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!

    roepke schrieb:

    Gibt es dafür eine Erklärung?
    Winforms-Controls sind Wrapper um äusserst ominöse Windows-BetriebsSystem - Funktionalitäten.
    Also wenn du Label1.Text="lkj" schreibst, wird das intern umgeleitet auf ieinen SendMessage an Window-Handle-Aufruf, oder mehrere.
    Diese internem SendMessage-Operationen sind nicht threadsicher.
    Nu kann sein, dass ein Control zusätzlich auch echte .Net-Funktionalität beinhaltet, weil man halt zusätzlich was drangebastelt hat.
    Wenn diese Zufügungen nicht ins Windows-SendMessaging-System eingreifen (etwa indem sie ihrerseits Label1.Text="???" aufrufen), machen sie auch kein Theater bei CrossThread-Calls.

    Langer Rede kurzer Sinn: Bei den meisten Control-Properties crashtes, aber nicht bei allen.

    RodFromGermany schrieb:

    Sowohl der 1. (1te, erste) als auch der 2. (2te, zweite) Thread sind offensichtlich NICHT GUI-Thead.

    Der erste Thread hat sehr wohl eine GUI, ist nämlich ein Form mit sichtbaren Controls. Der 2te Thread läuft unsichtbar im Hintergrund.
    Außerdem kann ich ja manche Controls lesen und manche schreiben, ohne Invoke, und manche eben nicht

    @ErfinderDesRades Wenn das so ein unübersichtliches KuddelMuddel ist, empfielt sich doch Invoke in jedem Fall, auch wenn es ohne ginge?

    roepke schrieb:

    empfielt sich doch Invoke in jedem Fall, auch wenn es ohne ginge?
    Das kann man so nicht stehen lassen, sonst müsste man ja immer schreiben: Me.BeginInvoke(Sub() TextBox1.Text = "Foo"). Und das wär ja hanebüchen. Also bitte nur dort, wo sicher ist, dass ein (schreibender) threadübergreifender Zugriff auf Controls des GUI-Threads erfolgt.
    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.
    OK, dann lasse ich überall wo nciht gemeckert das Invoke weg.
    Wie ist dass eigentlich konkret mit dem Invoke vs. BeginInvoke?
    Beim Schreiben einer Property (.Text = ...) klappt das synchron (Invoke) als auch asynchron (BeginInvoke).
    Beim Lesen sieht die Welt etwas anders aus. Invoke ja, BeginInvoke nur mittels Delegate , extra Klasse und Caller.
    Was die Sache etwas unübersichtlicher werden lässt.
    Braucht es nicht zwingend immer einen EndInvoke, oder kann ich den beim Schreiben einfach weg lassen?

    roepke schrieb:

    Der erste Thread hat sehr wohl eine GUI
    Du hast also zwei GUI-Threads.
    Wann wolltest Du uns darüber informieren?
    Kannst Du mal das Gesamt-Konstrukt erläutern?
    =====

    roepke schrieb:

    Wie ist dass eigentlich konkret mit dem Invoke vs. BeginInvoke?
    Invoke() führt die Aktion sofort aus.
    BeginInvoke() wartet auf ein Idle der GUI.

    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 Jetzt verstehe ich's gerade nicht?
    Ich habe eine Form (1. Thread). In deren .Load() wird ein 2ter Thread erstellt, der damit beschäftigt ist abhängig von Einstellungen auf dem Form (ComboBox, TextBox, CheckBox) Daten im Hintergrund {.IsBackground = True} via GPIB von Messegeräten zu lesen und damit das Label im Form zu füllen. So gesehen ist der 2te Thread doch kein GUI Thread? Oder eben doch, weil er Daten von Thread 1 bekommt und dort hin zurück liefert?

    Der Unterschied der beiden Invokes ist mir schon klar, nur wie ist das mit dem EndInvoke? Beim Schreiben optional oder gar nicht nötig. Wüste auch gar nicht wo ich das wie setzen sollte bei einem Me.BeginInvoke(Sub() TextBox1.Text = "Foo")

    RodFromGermany schrieb:

    Invoke() führt die Aktion sofort aus.
    BeginInvoke() wartet auf ein Idle der GUI.
    Sicher, dass das nicht andersrum ist? Bzw. Invoke wartet, bis der GUI-Thread fertig ist und BeginInvoke das ganze anfängt und dann gleich mit der nächsten Sache weitermacht.
    EndInvoke scheint tatsächlich optional zu sein, auch wenn mir das immer noch komisch vorkommt.

    ##########

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Await Threading.Tasks.Task.Run(Sub() Foo)
    3. End Sub
    4. Private Sub Foo()
    5. Me.BeginInvoke(Sub() Bar())
    6. Stop
    7. End Sub
    8. Private Sub Bar()
    9. Threading.Thread.Sleep(1000)
    10. Button1.Text = "asd"
    11. End Sub

    Mit Invoke, dauert es eine Sekunde bis zum Stop, mit BeginInvoke wird das Stop sofort erreicht.
    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.

    VaporiZed schrieb:

    Sicher, dass das nicht andersrum ist?
    Ich habs mal untersucht:
    Untersuchungen zu Invoke() und BeginInvoke() - Reihenfolge der Abarbeitung
    ================
    Wenn der erste (oder 1.) (nicht aber 1te, 2te usw.) Thread der "normale" GUI-Thread ist, dann benenne ihn so, damit es zu keinen Verwirrungen kommt. ;)
    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!
    wenn ich recht erinnere waren deine Untersuchungen nicht korrekt, oder untersuchten nicht, was wichtig ist.
    Invoke und BeginInvoke führen beide die Aktion auf dieselbe Weise aus - keine Ahnung, ob sie auf ein Idle warten oder wann auch immer - jdfs. machens beide gleich.
    Der Unterschied ist, dass der NebenThread bei Invoke wartet, bis der Gui-Thread mit dem Invoke durch ist.
    Und dieses Warten ist üblicherweise völlig unnütz - hätte ja nur Sinn, wenn der NebenThread Ergebnisse des Gui-Threads verarbeiten wollen würde.