Benutzer mit den meisten Antworten
form1, class, event = System.InvalidOperationException

Frage
-
Hallo, allerseits!
Ich möchte gerne Buttons eines Controllers (XBox360 über Bluetooth-Adapter) abfragen und deren Status auf einem Form (Checkbox) darstellen.
Das Einlesen der Werte geschieht über eine Klasse, die diese Werte in Variablen speichert und über Property zur Verfügung stellt.
Erster Ansatz war also:
form1
private x as new x_class
timer_tick
chk01.checked = x.a
chk02.checked = x.b [ usw. ]x_class
private _a as boolean
private _b as boolean [ usw. ]
public readonly property a as boolean
get
getvalues()
return _a
public readonly property b as boolean [ usw. ]
private sub getvalues()
_a = …
_b = … [ usw. ]Das funktionierte soweit auch ganz gut, aber mich störte das getvalue() in jeder einzelnen Property, um die jeweils aktuellen Werte zu erhalten. Also habe ich einen Thread gebaut, der die Werte kontinuierlich im Hintergrund aktualisiert:
x_class
public sub new()
_poll = new thread(addressof polltask)
_poll.isbackground = true
_poll.start()
private sub polltask()
_a = …
_b = … [ usw. ]Auch das funktionierte prima. Jetzt wollte ich aber noch einen Schritt weiter gehen. Das Hauptprogramm (also Form1) setzt ja immer und immer wieder in einer Endlos-Schleife die Werte. Da finde ich es ja besser, wenn dort nur Aktualisierungen gemacht werden, wenn sich Werte ändern. Also hab ich mir mal die Event-Auslösung und den Parameter EventArgs angesehen. Heraus kam eine von EventArgs abgeleitete Klasse, das RaiseEvent beim Auslesen der Werte (wenn sie sich ändern) und die Handler im Hauptprogramm.
In den EventArgs speichere ich eine ID, den Namen und den Wert. Über die ID kann ich dann später die CheckBox bestimmen, die gesetzt werden soll.
x_eventargs
inherits eventargs
private _b As integer
private _bn As string
private _bv As Boolean
public readonly property b as integer
get
return _b
end get
[ Properties für _bn und _bv ]x_class
private sub polltask()
dim e as new x_eventargs
[ wenn neuer Wert <> altem Wert ]
e.b = …
e.bn = …
e.bv = …
raiseevent change(me, e)form1
private sub x_change(sender as object, e as x_eventargs) handles x.change
dim o as checkbox
if (e.b = 1) then o = chk01 [ tatsächlich per select case … ]
o.checked = e.bvAber das geht jetzt nicht mehr, und ich verstehe nicht so recht, warum nicht. Es kommt zu einem Fehler system.invalidoperationexception, weil die CheckBox in einem anderen Thread gesetzt werden soll, als dem, in dem sie erzeugt wurde. Aber das würde je bedeuten, daß der Handler in einem anderen Thread läuft. Irgendwo gesagt habe ich das m.W.n. aber nicht. Ich dachte eigentlich, das Einzige, was in einem anderen Thread läuft, ist das Abfragen der Werte und Setzen der internen Variablen in der x_class. Das Abfragen dieser Variablen geschieht doch wieder im Haupt-Thread über die Properties, oder etwa nicht?
Wo ist da jetzt mein Gedankenfehler und wie korrigiere ich das?
Gruß, Michael
Antworten
-
Hi Michael,
wenn Du den BackgroundWorker nutzt, dann läuft DoWork in einem separaten Thread. Aus diesem dort laufenden Code kannst Du nicht auf Steuerelemente zugreifen, da in diesem Fall ein Fehler wegen thread-übergreifendem Zugriff geworfen wird. Die Ereignisse für den Fortschritte und Completed des BackgroundWorkers werden im Kontext das Ausgangs-Threadfs ausgeführt und da gibt es keine Fehler wegen thread-übergreifendem Zugriff.Wenn Du auf Steuerelemente im Haupt-Thread aus einem anderen Thread zugreifen willst, dann kannst du Die Invoke-Methode des betreffenden Steuerelementes nutzen. Das kann bei mehreren Steuerelementen etwas Aufwändig werden, weshalb in solchem Fällen besser der SynchrnizationContext genutzt werden kann.
Beispiel eines Zugriffs auf eine Checkbox:
' Beispiel für den Thread Sub myThread() Do System.Threading.Thread.Sleep(100) SetValue(true) Loop End Sub ' irgendwo ist die Checkbox deklariert, z.B. im Designer-File Private cb As New CheckBox ' Deklaration des Typs des Sprungbefehls Delegate Sub SetValueDeleg(value As Boolean) ' Wert im Steuerelement setzen Sub SetValue(value As Boolean) ' prüfen, ob aus anderem Thread zugegriffen wird. If cb.InvokeRequired Then ' wenn ja, dann ein Invoke ausführen cb.Invoke(New SetValueDeleg(AddressOf SetValue), value) Else cb.IsChecked = Value End If End Sub
Mit dem SynchronizationContext kann man beispielsweise so arbeiten:
Option Infer On Option Strict Off Imports System.Threading ''' <summary>Klasse mit gekapselten Methoden, ''' die in separaten thread abgearbeitet werden</summary> Public Class Class1 ''' <summary>Ereignis zum Rückmelden des Zustandes</summary> Public Event Ereignis(ByVal txt As String) ''' <summary>Context das Ausgangsthreads merken</summary> Private sc As SynchronizationContext ''' <summary>Konstruktor, in dem der Einfachkeit halber gleich der thread gestartet wird</summary> Sub New() sc = SynchronizationContext.Current Call (New Thread(AddressOf thSub)).Start() End Sub ''' <summary>Methode, die als thread gestartet wird</summary> Private Sub thSub() ' Hier irgendwas machen und dann Ereignis auslösen sc.Post(New SendOrPostCallback(AddressOf RaiseEreignis), "Ereignis " & i.ToString) Next End Sub ''' <summary>Ereignis auslösen im Context des Ausgangsthreads</summary> Private Sub RaiseEreignis(ByVal state As Object) RaiseEvent Ereignis(state.ToString) End Sub End Class
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 15. November 2018 08:29
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 22. November 2018 13:15
-
Hi Michael,
schau Dir mal einen Beitrag von mir an unter:<Tipps und Tricks - informtools - Tipp 233>
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 15. November 2018 08:30
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 22. November 2018 13:15
-
Hi Michael,
und warum nutzt Du nicht die Variante mit dem SynchronizationContext? Nach Deinen Schilderungen würde sie am besten zu Deinen Anforderungen passen.Auf DoEvents solltest Du vollständig verzichten. Das ist bei passendem Programmdesign nicht erforderlich. Mit DoEvents hältst Du nur den aktuellen Thread an, damit im aktuellen Thread anhängige abzuarbeitende Routinen ausgeführt werden. Früher wurde DoEvents üblicherweise im UI Thread genutzt, um einem RefResh der Oberfläche Zeit zu geben.
Wenn Du den Thread mit DoWork des BackgroundWorkers nutzt und darin Deine Check-Routine aufrufst, dann nutze in der Ckeck-Routine das SynchronizationContext.Post. Die möglichen Sprungziele (delegates) kannst Du vor dem Start des BackgroundWorkers festlegen, ähnlich dem Abonnieren eines Ereignisses. Die Check-Routine prüft den Verarbeitungszustand der Schleife im Dowork und wählt das betreffenden Sprungziel (delegate) aus.
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 15. November 2018 08:30
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 22. November 2018 13:15
Alle Antworten
-
Hi Michael,
polltask läuft in einem separaten thread. In diesem thread wird RaiseEvent ausgelöst. Ein Event (Ereignis) ist intern nichts anderes als ein delegate, der die Adresse der Ereignisroutine enthält (falls das Ereignis abonniert wurde). Beim RaiseEvent wird diese Ereignisroutine aufgerufen und abgearbeitet (wenn abonniert). Diese Abarbeitung läuft im Kontext des threads, in dem polltask läuft. Wenn in dieser Ereignisroutine z.B. auf Eigenschaften der Oberfläche zugegriffen wird, gibt es wegen thread-übergreifenden Zugriff einen Fehler.Das Problem kann man lösen, indem der Zugriff auf die Oberflächen-Elemente im thread ausgeführt wird, in welchem das Oberflächen-Element erzeugt wurde, das bedeutet im Normalfall im Haupt-Thread, in welchem das Programm gestartet wurde. Das kann man auf verschiedene Art und Weise erreichen:
1. BackgroundWorkers anstelle _poll.Start
2. Invoke-Methode des Steuerelementes (in der Ereignis-Routine)
3. SynchronizationContext.Post anstelle RaiseEvent
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks -
Hallo, Peter!
Zunächst erstmal recht herzlichen Dank für Deine schnelle Antwort. Ich bin bereits am Basteln und Probieren. Wenn ich ein Ergebnis habe, melde ich mich auf alle Fälle nochmal.
Zwischenstand bis dahin:
Backgroundworker hab ich schonmal irgendwo benutzt. Ich glaube, das war bei irgendeiner elend langen SQL-Abfrage. Das Ding such ich nochmal, könnte aber tatsächlich eine gute Methode sein.
Invoke, muß ich ehrlich sagen, verstehe ich noch nicht so recht. Oder es macht nicht das, was ich möchte / brauche. Wenn ich es mit Invoke schaffe, das Event im Main-Thread auszulösen, dann wär alles gut. Wenn ich im Main-Thread aber nur per Invoke das Checkbox1.Checked setzen kann, dann ist das irgendwie nicht so das Wahre. Ich möchte sozusagen "wie gewohnt" im Main auf ein Event reagieren, ohne dort jedesmal dran denken zu müssen, ob das Event aus dem gleichen Thread kommt, oder nicht.
SynchronizationContext.Post kenne ich noch gar nicht, werd ich mir aber auch mal ansehen. Aber z.Z. tendiere ich zum Bgw.
Gruß, Michael
-
Hi Michael,
schau Dir mal einen Beitrag von mir an unter:<Tipps und Tricks - informtools - Tipp 233>
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 15. November 2018 08:30
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 22. November 2018 13:15
-
Hallo, Peter!
Also, kurz gesagt: Das Problem besteht weiterhin.
a) BackgroundWorker: Ich hab meinen alten Source gefunden und es ging wirklich um eine SQL-Abfrage, die länger dauert und deswegen im Hintergrund ablaufen sollte. Vereinfacht: Im bgw_DoWork() wurde die Abfrage gestartet und im bgw_RunWorkerCompleted() wurde das Ergebnis in eine ListBox übertragen. Damals hatte ich aber wohl auch die Komponente auf's Formular gezogen. Ok, läßt sich ja auch zur Laufzeit erstelllen.
Ablauf bisher: class x - New() - PollTask() als Thread - dort wird ggf. ein RaiseEvent() gemacht.
Ablauf jetzt: class x - New() - RunWorkerAsync() - DoWork() - dort wird ggf. ein RaiseEvent() gemacht.
(Sowohl im PollTask() wie auch im DoWork() wird in einer Do..Loop-Endlosschleife die Sub Check() aufgerufen - genau genomen wird _dort_ das RaiseEvent durchgeführt.)
Und die Fehlermeldung ist exakt die gleiche, wenn ich auf das Event in Form1 reagieren will, indem ich eine CheckBox1.Checked ändere: Falscher Thread
b) Invoke: Ich krieg's nicht hin, befürchte aber auch, daß ich den falschen Ansatz habe. Und ich befürchte weiterhin, daß der richtige Ansatz nicht das ist, was ich haben möchte.
Was ich möchte: In Form1 den einen oder anderen Event-Handler:
Private Sub x_Event1(Sender As Object, e As x_Args) Handles x.myEvent1
CheckBox1.Checked = True
End Sub
Und der soll auch wirklich nur so aussehen. Ich möchte mich dort nicht darum kümmern müssen, ob das Event im korrekten Thread ausgeführt wird, oder nicht. Und ob ich dort eine CheckBox ändere, einen Sound abspiele oder den Rechner ausschalte, entscheide ich erst und nur dort. Die x-Klasse soll sich darum nicht kümmern.Wenn ich das mit dem Invoke aber richtig verstehe, dann muß ich dort bereits die CheckBox1 angeben. Und das ist eben das, was nicht geht. Ich will nur wissen, ob eine Taste gedrückt oder losgelassen wird, genau wie KeyDown() oder MouseUp()-Ereignsse.
Also: Wie löse ich das Event (und nur das) so aus, daß es im Thread des Form1 aufschlägt und nicht in einem Hintergrund-Thread? Also so, daß die weitere Bearbeitung des Events dort ohne weitere Maßnahmen Zugriff auf die Formular-Elemente zuläßt?
Wo ist die Kneifzange? Ich scheine 'n Haufen Bretter vor den Kopf genagelt zu haben.
Gruß, Michael
-
Hi Michael,
wenn Du den BackgroundWorker nutzt, dann läuft DoWork in einem separaten Thread. Aus diesem dort laufenden Code kannst Du nicht auf Steuerelemente zugreifen, da in diesem Fall ein Fehler wegen thread-übergreifendem Zugriff geworfen wird. Die Ereignisse für den Fortschritte und Completed des BackgroundWorkers werden im Kontext das Ausgangs-Threadfs ausgeführt und da gibt es keine Fehler wegen thread-übergreifendem Zugriff.Wenn Du auf Steuerelemente im Haupt-Thread aus einem anderen Thread zugreifen willst, dann kannst du Die Invoke-Methode des betreffenden Steuerelementes nutzen. Das kann bei mehreren Steuerelementen etwas Aufwändig werden, weshalb in solchem Fällen besser der SynchrnizationContext genutzt werden kann.
Beispiel eines Zugriffs auf eine Checkbox:
' Beispiel für den Thread Sub myThread() Do System.Threading.Thread.Sleep(100) SetValue(true) Loop End Sub ' irgendwo ist die Checkbox deklariert, z.B. im Designer-File Private cb As New CheckBox ' Deklaration des Typs des Sprungbefehls Delegate Sub SetValueDeleg(value As Boolean) ' Wert im Steuerelement setzen Sub SetValue(value As Boolean) ' prüfen, ob aus anderem Thread zugegriffen wird. If cb.InvokeRequired Then ' wenn ja, dann ein Invoke ausführen cb.Invoke(New SetValueDeleg(AddressOf SetValue), value) Else cb.IsChecked = Value End If End Sub
Mit dem SynchronizationContext kann man beispielsweise so arbeiten:
Option Infer On Option Strict Off Imports System.Threading ''' <summary>Klasse mit gekapselten Methoden, ''' die in separaten thread abgearbeitet werden</summary> Public Class Class1 ''' <summary>Ereignis zum Rückmelden des Zustandes</summary> Public Event Ereignis(ByVal txt As String) ''' <summary>Context das Ausgangsthreads merken</summary> Private sc As SynchronizationContext ''' <summary>Konstruktor, in dem der Einfachkeit halber gleich der thread gestartet wird</summary> Sub New() sc = SynchronizationContext.Current Call (New Thread(AddressOf thSub)).Start() End Sub ''' <summary>Methode, die als thread gestartet wird</summary> Private Sub thSub() ' Hier irgendwas machen und dann Ereignis auslösen sc.Post(New SendOrPostCallback(AddressOf RaiseEreignis), "Ereignis " & i.ToString) Next End Sub ''' <summary>Ereignis auslösen im Context des Ausgangsthreads</summary> Private Sub RaiseEreignis(ByVal state As Object) RaiseEvent Ereignis(state.ToString) End Sub End Class
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 15. November 2018 08:29
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 22. November 2018 13:15
-
Hallo, Peter!
Hmmm... Also... a) Es funktioniert b) nicht so, wie ich eigentlich möchte. Aber grundsätzlich ist Invoke() wohl noch der geringste Aufwand:
Public Class Form1 Private WithEvents xb360 As New Xbox360Controller Delegate Sub setCheckBoxDelegate(n As Integer, v As Boolean) Delegate Sub setProgressBarDelegate(n As Integer, v As Single) Private Sub setCheckBox(n As Integer, v As Boolean) Dim o1 As CheckBox Select Case n Case 1 : o1 = Me.chk_B_A ' ... 14 Case Else o1 = Nothing 'Debug.Print("unknown button: " & n) End Select If (Not o1 Is Nothing) Then If (o1.InvokeRequired) Then o1.Invoke(New setCheckBoxDelegate(AddressOf setCheckBox), n, v) Else o1.Checked = v End If End If End Sub Private Sub setProgressBar(n As Integer, v As Single) Dim o1 As ProgressBar : Dim o2 As Label : Dim v2 As Single Select Case n Case 1 : o1 = Me.prg_LeftX : o2 = Me.lbl_LeftX : v2 = Int(v * 50) + 50 ' ... 6 Case Else o1 = Nothing : o2 = Nothing : v2 = 0 'Debug.Print("unknown axis: " & n) End Select If (Not o1 Is Nothing) Then If (o1.InvokeRequired) Then o1.Invoke(New setProgressBarDelegate(AddressOf setProgressBar), n, v) Else o1.Value = v2 : o2.Text = v End If End If End Sub Private Sub xb360_ButtonDown(Sender As Object, e As xb360EventArgs) Handles xb360.ButtonDown 'Debug.Print("Event: " & e.ButtonName & " (" & e.ButtonNumber & ") down") setCheckBox(e.ButtonNumber, True) End Sub Private Sub xb360_ButtonUp(Sender As Object, e As xb360EventArgs) Handles xb360.ButtonUp 'Debug.Print("Event: " & e.ButtonName & " (" & e.ButtonNumber & ") up") setCheckBox(e.ButtonNumber, False) End Sub Private Sub xb360_AxisMove(Sender As Object, e As xb360EventArgs) Handles xb360.AxisMove 'Debug.Print("Event: " & e.AxisName & " (" & e.AxisNumber & ") = " & e.AxisValue) setProgressBar(e.AxisNumber, e.AxisValue) End Sub End Class
Mich stört eben Folgendes:
Delegate Sub setCheckBoxDelegate(n As Integer, v As Boolean) Delegate Sub setProgressBarDelegate(n As Integer, v As Single) [ ... ] If (o1.InvokeRequired) Then o1.Invoke(New setCheckBoxDelegate(AddressOf setCheckBox), n, v) Else o1.Checked = v End If [ ... ] If (o1.InvokeRequired) Then o1.Invoke(New setProgressBarDelegate(AddressOf setProgressBar), n, v) Else o1.Value = v2 : o2.Text = v End If
Ich muß im Form1 immer daran denken, die Delegates zu deklarieren und den Zugriff auf die Formular-Elemente mit dem InvokeRequired zu kapseln. Geht das denn partout nicht auch ohne das?
Aber ok, wenn es wirklich nicht anders geht, dann muß ich mich eben daran gewöhnen - irgendwo in der Klasse dann ein paar Kommentarzeilen mit dem Krams als Gedankenstütze oder so. ;-)
Vielen Dank in jedem Fall für die Hilfe. Ich schau mal, welches Posting am besten als "Antwort" zu markieren ist.
Gruß, Michael
-
Hallo nochmal, Peter!
Nachtrag: Ich werde nochmal etwas mit dem ReportProgress() für den BackgroundWorker experimentieren. Vielleicht spare ich mir das Invoke() dann ja doch noch. Ich melde mich dann nochmal... ;-)
Wenn das funktioniert, dann war der entscheidende Hinweis, daß nicht nur Completed, sondern auch Progress bereits wieder im Haupt-Thread laufen. Den Hinweis hätte ich beinahe überlesen.
Gruß, Michael
-
Hi Michael,
natürlich geht das auch anders. Ein Beispiel dazu hatte ich Dir gezeigt. Du kapselst alles zum separaten Thread in einer Klasse, die vom UI-Thread instanziiert wird. Beim Instanziieren merkst Du Dir den aktuellen SynchonizationContext. Alle CallBacks aus dieser Klasse, die auf den UI-Thread wirken, rufst Du mit SynchonizationContext.Post auf.--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks -
Hi Michael,
blöd ist nur, dass im Progress-Ereignis nur eine Zahl (Fortschritts-Prozent) übergeben werden kann.--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks -
Hallo, Peter!
Ja, ich schätze, darüber stolpere ich gerade. Ok, ich kann pauschal ReportProgress(50) machen, wenn ich die zu verarbeitenden Werte denn woanders liegen habe. Dachte ich...
Mein Ansatz bis eben: Die Check() Routine löst die Events nicht direkt selbst aus, sondern legt die EventArgs in eine Klassen-globale private List(Of xb360EventArgs) ab und übergibt ein True zurück, wenn mind. ein Event neu dazu gekommen ist.
DoWork ruft Check() und bei True dann direkt ReportProgress() auf und wartet dann in einer While-Schleife mit DoEvents() darauf, daß die List() wieder leer ist. Das ganze wiederholt sich dann in einer Do..Loop.
ProgressChange ruft dann für jedes Element der List() das passende RaiseEvent auf und löscht das Element dann aus der Liste. Soweit der Plan...
In der ProgressChange: Der List.Count ist > 0 (i.a. 1), aber die Elemente sind irgendwie leer. Z.B. die List(0).ButtonNumber (sollte 1..14) ist immer 0. Es wird zwar das Event ausgelöst, aber wegen der 0 passiert nix.
Löse ich in der Check() das RaiseEvent direkt aus, geht alles wie gewollt. Also scheint irgendwas beim List.Add vom einen Thread (BackgroundWorker) in den anderen (Form1) verloren zu gehen. Merkwürdigerweise packt er ja ein Element in die Liste, aber die Member sind auf 0. Mal sehen, ob ich dem auch noch auf die Spur komme...
Gruß, Michael
-
Hi Michael,
und warum nutzt Du nicht die Variante mit dem SynchronizationContext? Nach Deinen Schilderungen würde sie am besten zu Deinen Anforderungen passen.Auf DoEvents solltest Du vollständig verzichten. Das ist bei passendem Programmdesign nicht erforderlich. Mit DoEvents hältst Du nur den aktuellen Thread an, damit im aktuellen Thread anhängige abzuarbeitende Routinen ausgeführt werden. Früher wurde DoEvents üblicherweise im UI Thread genutzt, um einem RefResh der Oberfläche Zeit zu geben.
Wenn Du den Thread mit DoWork des BackgroundWorkers nutzt und darin Deine Check-Routine aufrufst, dann nutze in der Ckeck-Routine das SynchronizationContext.Post. Die möglichen Sprungziele (delegates) kannst Du vor dem Start des BackgroundWorkers festlegen, ähnlich dem Abonnieren eines Ereignisses. Die Check-Routine prüft den Verarbeitungszustand der Schleife im Dowork und wählt das betreffenden Sprungziel (delegate) aus.
--
Viele Grüsse
Peter Fleischer (ehem. MVP für Developer Technologies)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 15. November 2018 08:30
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Donnerstag, 22. November 2018 13:15
-
und warum nutzt Du nicht die Variante mit dem SynchronizationContext? Nach Deinen Schilderungen würde sie am besten zu Deinen Anforderungen passen.
Hallo, Peter!
Ich hatte mir das als letztes angesehen, weil ich das bis dato noch gar nicht kannte. Aber Tatsache ist: Es scheint die einzige Möglichkeit zu sein, das hinzubekommen. Insofern ist dieser Post dann auch die Antwort, was Ivan ja aber auch schon markiert hat.
Nur der "BackgroundWorkers anstelle _poll.Start" reicht auf alle Fälle nicht. Das "anderer Thread" Problem bleibt dadurch bestehen.
Die "Invoke-Methode" galt es zu vermeiden.
Aber "SynchronizationContext.Post anstelle RaiseEvent" in der Klasse war letztendlich die Lösung. Die gefällt mir, nachdem ich jetzt ein wenig damit herumgespielt habe, auch so gut, daß ich mein altes Projekt (lang dauernde SQL-Query) auch auf diese Methode umstellen werde.
Vielen Dank nochmals für die Hilfe!
Gruß, Michael