Autor Beitrag
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 04.03.10 17:43 
Hallo zusammen,

ich habe eine Verarbeitungsroutine die durch einen Trigger ausgelöst wiederum andere Verarbeitungsroutinen ausführt. Das zusammensetzen der Abläuft geschieht in einem Designer und wird in eine Konfigurationsdatei gespeichert - soweit so gut.

Nun will ich bei einer Verarbeitungsroutine ein Form anzeigen lassen, welches auch eine WebBrowser-Control hat. Zur Laufzeit bekomme ich folgende Fehlermeldung.
ausblenden Quelltext
1:
2:
System.Threading.ThreadStateException
{"Das ActiveX-Steuerelement 8856f961-340a-11d0-a96b-00c04fd705a2 kann nicht instanziiert werden, da der aktuelle Thread kein Singlethread-Apartment ist."}


Ich habe leider keinen Verweis auf die Basisform.

Wie kann ich dies lösen?

Danke & Gruß
Daniel
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 04.03.10 18:03 
Zitat aus der MSDN zu Webbrowser
Zitat:
The WebBrowser class can only be used in threads set to single thread apartment (STA) mode. To use this class, ensure that your Main method is marked with the STAThreadAttribute attribute.


Webbrowser und alle anderen ActiveX Geschichten gehen nur in STA Threads. Also entweder besagtes STAThreadAttribute Attribute verwenden oder den ApartmentState des Threads direkt setzen.

ausblenden C#-Quelltext
1:
2:
3:
    Thread meinLieberThread = new Thread(new ThreadStart(meinLiebeThreadMethode));
    meinLieberThread.SetApartmentState(ApartmentState.STA);
    meinLieberThread.Start();
danielf Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 04.03.10 18:16 
Danke für die Antwort.

Meine Main ist als STAThread deklariert. Einen Thread mit ApartmentState.STA zu erstellen habe ich auch erfolglos versucht.

ausblenden C#-Quelltext
1:
2:
3:
Thread t = new Thread(new ParameterizedThreadStart(ShowTriggerParas));
t.SetApartmentState(ApartmentState.STA);
t.Start(paras);


Aber mit ist gerade aufgefallen, dass das Fenster beim ersten Mal kurz aufgeht und dann sofort wieder verschwindet.

Ich brächte irgendwie ein dynamisches Callback Szenario das keinen Verweis braucht :/

Im Prinzip geht es darum, wenn in der Abarbeitungskette ein Fehlerauftritt, diese ggf. in einem Forum auf poppen zu lassen. Das Problem ist aber, dass ich diese beschreibend Abspeichere und die Prozesse "gleich" behandle. Soll ich nun jedem Handler das MainForm für ein Invoke mitgeben?

Glaub ich hab da einen Knoten rein gemacht :(
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 04.03.10 18:37 
Zitat:
Glaub ich hab da einen Knoten rein gemacht :(

Wenn ich versuche dein Problem zu verstehen, das du in den letzten 2 Absätzen beschreibst, fühle ich mich auch ziemlich verknotet ;) Wenn du es ein wenig klarer ausgedrückt bekommst kann man dir vielleicht helfen.
danielf Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 04.03.10 19:09 
Okay, ich versuche es nochmal:

Ich habe Trigger welche eine Verarbeitungskette anstoßen. Das ist sozusagen die Quelle. Jeder Trigger hat eine Liste von Handlern die er wiederum aufruft. Ein Handler verarbeitet das Ergebnis und ruft ggf. wiederum Handlers auf. Am Ende gibt es noch Aktionen die ausgeführt werden können, wie zum Beispiel speichere Wert xy in Datenbank oder sende e-Mail an xy .... und eine Aktion soll eben ein Form aufmachen.

Zum Beispiel:
IntervalTrigger (wird alle 10 Sekunden ausgeführt) ruft Decmalhandler auf -> DecimalHandler (schaut ob Wert x > y ist) -> ActionHandler (führt verschiedene Aktionen aus)

ähm.. einigermaßen angekommen?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 04.03.10 19:54 
Soweit verständlich. Aber es ging los mit einem Thread Problem und dann erwähntest du was von Callbacks ohne Verweis. Wo du beides unterbringst hast du verschwiegen(oder ich übersehe was). Gibt es die Callback und Threading Problematik zwischen den Handlern oder zwischen Handlern und dem was du Mainform nennst oder an anderer Stelle?

Ohne Detailwissen hört sich das für mich nach einem Einsatzzweck für ein Publisher/Subscriber Pattern bzw. Mediator Pattern an.
Beispiele (mit Source) wären zum Beispiel der EventBroker in SCSF/CAB oder der EventAggregator in Prism.
danielf Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 04.03.10 20:26 
Ich habe das Thread-Problem und bin deshalb am überlegen ob ich auf Callbacks umstelle, aber das Hilf auch nicht wirklich.

Vlt. ist ein Publisher/Subscriber gar nicht schlecht, wobei ich dann wieder "irgendwas" referenzieren muss. Mediator muss ich mir erstmal durchlesen.

Dann muss ich halt die Objekte selber laden und registrieren. Momentan kann ich alles ohne Aufwand serialisieren/deserialisieren ohne Events ohne Ähnliches zu registrieren - das war der Grundgedanke.

Danke für den Hinweis, mal noch bisschen grübeln :D
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 05.03.10 00:23 
user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe leider keinen Verweis auf die Basisform.
Wenn du das unbedingt, auch über einen Delegate, vermeiden willst, schau dir mal SynchronizationContext.Post an.

_________________
>λ=
danielf Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Fr 05.03.10 11:04 
Vielen Dank kha. Die Technik soll wohl genau mein Problem lösen :)

Auf Codeproject habe ich einen geeigneten Artikel über Understanding SynchronizationContext gefunden, der mir Hilft den Ansatz zu verstehen. So wie es scheint muss ich den einzelnen Threads trotzdem das SynchronizationContext mitgeben, lediglich die Verarbeitung bleibt dynamisch (in der Regel der MainThread).

Für mich heißt das wohl, dass ich jede Prozesskette in einem eignen Thread laufen lasse (macht ja auch Sinn), der bei Bedarf ein Post auf den UI-Thread macht.

Also danke nochmal, das Stichwort ist super :)

Hilft bestimmt auch anderen.

Gruß Daniel
danielf Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Fr 05.03.10 11:30 
Funktioniert 1A mit * :zustimm:!

Und den Verweis habe ich einfach in die Settings aufgenommen. (Die sollten nun halt aus dem UIThread geladen werden oder man muss den SyncContext nochmal neu setzen).

Auf jeden ist das nun schick :D
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 05.03.10 21:11 
Ups, dachte eigentlich, dass der SynchronizationContext an Child Threads vererbt wird :gruebel: . Solange man also nicht selbst SetSynchronizationContext setzt, gibt es doch eigentlich keinen Unterschied zu einem Delegate - außer ein paar Methoden mehr ;) .

_________________
>λ=
danielf Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Mo 08.03.10 07:34 
Also ich finde es praktischer, da ich kein konkretes Objekt angeben muss.

Ich instantiiere das Objekt aus dem UI-Thread und kann so innerhalb des Objektes über den SynchronizationContext.Current setzen. Wenn ich das Objekt dann aus einem anderen Thread aufrufe, brauche ich keine Abfrage ob ein Invoke nötigt ist oder nicht, sondern rufe die entsprechende Methode über ein Send (synchron) oder Post (asynchron) auf. So kann ich die Klasse (mit der kleinen Einschränkung, dass ich sie im UI-Thread erzeugen muss) problemlos wiederverwenden.

Also falls ich noch was negatives oder positives mit dieser Lösung erfahre, werde ich hier Bescheid geben - aktuell bin ich glücklich ;)

MFG Daniel