Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Threadübergreifender Zugriff auf GUI-Elemente ohne Control.Invoke
DiViP
myCSharp.de - Member



Dabei seit:
Beiträge: 27

Themenstarter:

Threadübergreifender Zugriff auf GUI-Elemente ohne Control.Invoke

beantworten | zitieren | melden

Hallo,

Wenn man aus einem fremden Thread GUI-Elemente verändert tritt bekanntlich eine Exception auf, wegen einer threadübergreifenen Veränderung von GUI-Elementen. Dieses Problem könnte man mit Control.Invoke lösen, aber das gefällt mir nicht, da ich die Sources der Form so einfach wie möglich halten will.
Wie ist es möglich, dass der fremde Thread sich darum kümmert, dass ein bestimmtes Event welches GUI-Elemente ändert, innerhalb des GUI-Threades aufgerufen wird. Ich möchte aber nicht dass der fremde Thread Control.Invoke auffruft, da dieser Thread nichts von dem Control wissen soll. Backgroundworker geht auch nicht, da ich diesen fremden Thread nicht selbst starte.
Kann man in einem fremden Thread eine Methode mit Parametern an den GUI-Thread hängen, welche dann innerhalb des GUI-Threades aufgerufen wird?

Ich hoffe meine Erklärung war verständlich. :)

mfg
DiViP
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von DiViP am .
private Nachricht | Beiträge des Benutzers
esskar
myCSharp.de - Member

Avatar #avatar-2885.jpg


Dabei seit:
Beiträge: 206
Herkunft: Dubai

beantworten | zitieren | melden

wenn der thread, nix von dem control weiß, wie ändert er es dann?
private Nachricht | Beiträge des Benutzers
ujr
myCSharp.de - Experte



Dabei seit:
Beiträge: 1770

beantworten | zitieren | melden

Hallo,

hast Du schon die Forumssuche bemüht? Diese Fragestellung wurde schon (zu) oft beantwortet.

Ganz kurz: Der Thread stellt Ereignisse zur Verfügung, bei denen sich die GUI anmeldet und die dann in den Behandlungsroutinen das Control.Invoke/BeginInvoke aufruft - der Thread braucht die GUI nicht zu kennen.

Links auf weiterführende Beiträge hängst Du hier bitte an. Danke.
private Nachricht | Beiträge des Benutzers
DiViP
myCSharp.de - Member



Dabei seit:
Beiträge: 27

Themenstarter:

beantworten | zitieren | melden

@esskar:
Der Thread stellt einen EventHandler bereit, welcher ein Ereignis in der Formklasse auslöst. Dort werden dann die GUI Elemente bearbeitet. Da aber eben dieses Event aus einem anderen Thread ausgelöst wird, entsteht dann eine Exception ohne ein Invoke.

@ujr:
Ich habe die Suche benutzt und die Lösung war immer ein Control.Invoke, welches ich aber, wie ich schon schrieb, nicht nutzen möchte.
private Nachricht | Beiträge des Benutzers
tom-essen
myCSharp.de - Experte

Avatar #avatar-2140.png


Dabei seit:
Beiträge: 1928
Herkunft: NRW

beantworten | zitieren | melden

Hallo!

Control.Invoke ist meiner Meinung nach der beste Weg, um threadübergreifend die GUI zu beeinflussen, eine einfachere Lösung fällt mir jetzt auch nicht ein. Welche Bedenken hast du bzgl. des Sourcecodes? Unübersichtlichkeit, oder noch andere Aspekte?
Nobody is perfect. I'm sad, i'm not nobody
private Nachricht | Beiträge des Benutzers
ujr
myCSharp.de - Experte



Dabei seit:
Beiträge: 1770

beantworten | zitieren | melden

Zitat von DiViP
Ich habe die Suche benutzt und die Lösung war immer ein Control.Invoke,

Fein - Deine Frage ließ allerdings nicht darauf schließen. Z. B. weil eben durch die Verwendung einer Ereignisbehandlung der Thread die Controls eben nicht kennen muss.
Zitat
welches ich aber, wie ich schon schrieb, nicht nutzen möchte.

Die Erklärung fehlt bzw. ist nicht schlüssig.

P.S.: Schau Dir mal SynchronizationContext an.
private Nachricht | Beiträge des Benutzers
DiViP
myCSharp.de - Member



Dabei seit:
Beiträge: 27

Themenstarter:

beantworten | zitieren | melden

Zitat von ujr
Die Erklärung fehlt bzw. ist nicht schlüssig.
Die Erklärung habe ich gegeben. Der Source der Form soll so einfach wie möglich sein. Der Hauptteil spielt sich in einer DLL ab, dessen Ergebnisse in einer Form dargestellt werden sollen.
Zitat
P.S.: Schau Dir mal SynchronizationContext an.
Das ist es! Danke :)

Lösung

SendOrPostCallback OnCallback = null;
SynchronizationContext SyncContext;
//...
SyncContext = SynchronizationContext.Current; // wird im Constructor meiner Klasse aufgerufen
//...
SyncContext.Post(OnCallback, State); // wird im fremden Thread aufgerufen

OnCallback kann dann als Event im GUI-Thread verwendet werden und erzeugt dann keine Exception.

Vielen Dank!
mfg
DiViP
private Nachricht | Beiträge des Benutzers
ujr
myCSharp.de - Experte



Dabei seit:
Beiträge: 1770

beantworten | zitieren | melden

Zitat von DiViP
Die Erklärung habe ich gegeben. Der Source der Form soll so einfach wie möglich sein.

Das meinte ich mit "nicht schlüssig" - ich weiß nicht, wo Invoke den Source kompliziert/komplex macht. Ist das nur ein "Gefühl"?

Prinzipiell sieht es ja mit SynchronizationContext ähnlich aus. Der Vorteil dabei ist jedoch, dass auch andere Ausführungsmodelle (WinForms, WPF, eigenes) unterstützt werden.
private Nachricht | Beiträge des Benutzers
DiViP
myCSharp.de - Member



Dabei seit:
Beiträge: 27

Themenstarter:

beantworten | zitieren | melden

Zitat von ujr
Das meinte ich mit "nicht schlüssig" - ich weiß nicht, wo Invoke den Source kompliziert/komplex macht. Ist das nur ein "Gefühl"?

Invoke ist nicht komplex oder kompliziert, es sind aber ein paar Codezeilen mehr. ;) Ich bin was das angeht Perfektionist und möchte die Formseite so extrem! einfach halten, damit jeder User, die oben angesprochene DLL, ohne viel Aufwand/Wissen nutzen kann. (auch wenn ich in diesem Fall der einzige Nutzer bleiben werde :))

So genug, bevor das hier Off-Topic wird. :)
Danke nochmals.

mfg
private Nachricht | Beiträge des Benutzers
DavidT
myCSharp.de - Member

Avatar #avatar-3073.png


Dabei seit:
Beiträge: 1008
Herkunft: Winterberg

beantworten | zitieren | melden

Da du die Bib scheinbar für andere Entwickler einfach halten willst, lass dir gesagt sein das hier wohl die Merhheit der Leute Invoke kennt und dementsprechend deinen Code schneller mit Invoke verstehen wird als mit SynchronisationContext :)

Gruß David
private Nachricht | Beiträge des Benutzers
DiViP
myCSharp.de - Member



Dabei seit:
Beiträge: 27

Themenstarter:

beantworten | zitieren | melden

Zitat von DavidT
... die Merhheit der Leute Invoke kennt und dementsprechend deinen Code schneller mit Invoke verstehen wird als mit SynchronisationContext :)

SynchronisationContext bekommt der User doch gar nicht zu sehen, was genau das Ziel meiner Frage war. Der User bekommt eine Klasse mit einen Eventhandler, welcher die Daten liefert, die angezeigt werden sollen und dieses Event soll frei sein von zusätzlichen Code, welcher nur dazu dient Threadübergreifende Prozesse zu steuern.
private Nachricht | Beiträge des Benutzers
moson
myCSharp.de - Member

Avatar #avatar-7.jpg


Dabei seit:
Beiträge: 151

beantworten | zitieren | melden

CheckForIllegalCrossThreadCalls = false; wär auch ne Option, kann aber zu Problemen führen und sollte eigentlich nicht benutzt werden.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo moson,
Zitat
CheckForIllegalCrossThreadCalls = false; [...] kann aber zu Problemen führen und sollte eigentlich nicht benutzt werden.
kann und wird zu Problemen führen und ist deshalb gerade keine Option. CheckForIllegalCrossThreadCalls ist - wie auch in der :rtfm: Doku steht, nur für Debuggingzwecke gedacht. Im Release sollte bzw. darf es keine threadübergreifenden Zugriffe mehr geben.

herbivore
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5409

beantworten | zitieren | melden

@DiViP: in [ExtensionMethods] CrossThread-Calls habich die Invokereien komplett vom gui-code weggekapselt.

Zum Vergleich Invoking - Synchronisation-Context: Ich seh da keinen Unterschied an Kompliziertheit, obman nu schreibt
Context.Post(delegate,...)
oder
Control.Invoke(delegate,...)
Tatsächlich kannichmir nie merken, welches von beiden nun seinerseits den Nebenthread blockiert, da es auf die Ausführung im GuiThread wartet: Context.Post oder .Send ?

Bei Control weissichs: Invoke wartet, BeginInvoke nicht.
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
DiViP
myCSharp.de - Member



Dabei seit:
Beiträge: 27

Themenstarter:

beantworten | zitieren | melden

Zitat von ErfinderDesRades
Context.Post oder .Send ?

Danke für die Info. Diesen Aspekt hatte ich gar nicht beachtet, ist aber ein sehr schöner Vorteil vom Synchronisation-Context, das man hier die Wahl zwischen asynchron (Post) und synchron (Send) hat. Habe nun den Context in meinem Code auf Send umgestellt, damit der DLL-Thread nicht davon läuft, weil das könnte durchaus passieren, wenn die GUI ein bisschen was zu tun hat. :)

mfg
DiViP
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo DiViP,
Zitat
ist aber ein sehr schöner Vorteil vom Synchronisation-Context, das man hier die Wahl zwischen asynchron (Post) und synchron (Send) hat.
nur damit kein falsche Eindruck entsteht: Diese Wahl hat man bei Control.BeginInvoke (asynchron) Control.Invoke (synchron) auch.


Hallo ErfinderDesRades,
Zitat
Ich seh da keinen Unterschied an Kompliziertheit,
in der Kompliziertheit liegt der Unterschied auch nicht. Es geht viel wichtiger um die Entkoppelung. Bei der Verwendung von Control.Invoke/BeginInvoke muss man System.Windows.Forms an einer Stelle einbinden, die mit dem GUI nichts zu tun hat. Außerdem kann man die Bibliothek dann nur in Windows-Forms-Programmen benutzen, wogegen SynchronizationContext mit allen Anwendungsarten (Forms, WPF, Web, Console, ...) funktioniert.

herbivore
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5409

beantworten | zitieren | melden

Ja, aber dafür isses (innerhalb von WinForm) mit Control.Invoke, hier: Application.OpenForms[0].BeginInvoke (ausse CrossThreadCalls) nochn bischen einfacher zu benutzen, weil man muß keinen SynchronisationContext initialisieren, und bei der Initialisierung gewährleisten, dasses auch im GuiThread initialisiert ist.

(@DiviP: Intern leitet in WinForm der SynchronisationContext auch an Control.Invoke() weiter)
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
esskar
myCSharp.de - Member

Avatar #avatar-2885.jpg


Dabei seit:
Beiträge: 206
Herkunft: Dubai

beantworten | zitieren | melden

ja, er will das control aber nicht an seine DLL übergeben.
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5409

beantworten | zitieren | melden

Welches Control? Welche Dll?

Wie gesagt: [ExtensionMethods] CrossThread-Calls kapseln das ganze Brimborium weg, und man kann schreiben statt:


AsyncMethod(blabla);


CrossThreadX.RunAsync(AsyncMethod, blabla);
dann läufts im Nebenthread

oder statt:


GuiMethod(blabla);


CrossThreadX.RunGui(GuiMethod, blabla);
dann läufts im Guithread
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Khalid
myCSharp.de - Experte

Avatar #avatar-2534.gif


Dabei seit:
Beiträge: 3627
Herkunft: Hannover

beantworten | zitieren | melden

So wie ich das verstehe möchte DiVip eine unabhängige Klasse haben, also unabhängig von WinForms, WebForms etc. Bei deiner Extension Method müsste er aber ein Verweis auf System.Windows.Forms haben. Das fällt damit weg.
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5409

beantworten | zitieren | melden

Ich les immer nur, dass sein Code im Form möglichst einfach sein soll.

Und, dasser mit SynchronisationContext zufrieden ist, also was solls.

edit: :tongue:
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers