Event mit Parameter im Thread feuern - Threadübergreifender Vorgang

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von TRiViUM.

    Event mit Parameter im Thread feuern - Threadübergreifender Vorgang

    Schönen Samstag Morgen wünsche ich!

    zunächst muss ich einmal sagen, dass ich bereits einige Threads mit ähnlichen Themen gefunden habe, diese mir jedoch für so eine "simple" Aufgabe zu oversized bzw. nicht 100 %ig passend erscheinen...

    Ich habe eine Forms-Anwendung.
    Diese benutzt eine Klasse, welche ich erstellt habe.

    Diese Klasse instanziere ich mit WithEvents Test as new TestKlasse.
    In dieser Klasse habe ich mehrere Events, die in einem Thread der TestKlasse gefeuert werden.
    Diese Events beinhalten Parameter, die ich mir in verschiedenen Controls anzeigen lassen möchte. (Die zu übergebenen Parameter werden auch im Thread erzeugt).
    Wenn ich dies ohne Invoke mache, kommt die übliche Fehlermeldung:

    Quellcode

    1. Der Zugriff auf das Steuerelement TextBox1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
    Soweit für mich auch alles verständlich.

    Da ich diese Klasse in vielen meiner Projekten verwenden möchte, würde ich dieses Problem gern in der TestKlasse beheben, sofern das möglich ist.
    Ich kann in meiner Forms-Anwendung zwar die Controls invoken (Invoke(Sub() TextBox1.Text = Argument)), allerdings müsste ich das ja dann bei jedem Event machen, und das ist lästig.

    Gibt es eine elegante und vorallem einfache Lösung dafür?

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „TRiViUM“ ()

    ja, feuere das Event im Main-Thread.
    Das ist aber nur sinnvoll, wenn es nicht zu oft gefeuert wird, denn derleit Thread-Überquerungen sind kostspielig.
    Eine gute Art, Threadgrenzen zu überqueren bietet die Progress(Of T) - Klasse (du siehst, der generische T-Datentyp ermöglicht, jede Art von Daten typisiert zu transfereieren).
    Sample dazu ist auch in Async, Await und Task enthalten.

    ErfinderDesRades schrieb:

    wenn es nicht zu oft gefeuert wird
    ab wann ist es denn oft ?
    Wie oft es gefeuert wird hängt vom Benutzer ab, denke aber dass es schon nicht zu oft sein wird.
    Es geht mir letztendlich um eine TCP-Server-Klasse, wo ich Events wie UserConnected, UserDisconnected, UnautorizedUserBlocked usw. feuere.

    Desweiteren ist die ​Progress(Of T) - Klasse leider erst ab Framework 4.5 verfügbar. Ich wäre aber lieber darunter geblieben, XP-Nutzern zu liebe (davon solls ja auch noch welche geben :)).
    Ich wüsste allerdings auch noch nicht so richtig, wie ich das mit der beschriebenen Progress(Of T) - Klasse lösen soll.
    Es sind ja unterschiedliche Datentypen die ich beim entsprechenden Event abrufen kann. Oder übergebe ich den ganzen Thread?!
    Und woher weiß ich dann, welches Event gefeuert wurde?

    TRiViUM schrieb:

    Events wie UserConnected, UserDisconnected, UnautorizedUserBlocked usw. feuere.
    ja, sowas ist nicht zu oft.
    Zu oft wäre, wenn du eine Arbeitsschleife hast, und in jeder Umdrehung würde die ein Progresschanged feuern.

    Wenn die Progress(Of T) - Klasse nicht verfügbar ist, vlt kannst du was mit meinem AsyncWorker anfangen : codeproject.com/Articles/60382…ackgroundWorker-and-about
    damit kann man das auch lösen.

    Fakiz schrieb:

    In dieser Methode invokest du die Textbox
    das sind ja immer unterschiedliche Steuerelemente...und da muss ich ja bei jedem neuen Projekt wieder ein workaround in meiner GUI-Klasse machen...genau das möchte ich ja nicht. Da kann ich auch ruhig weiter die Controls invoken.

    @ErfinderDesRades
    zu dem AsyncWorker, das kommt meinem Vorhaben schon ziemlich nahe, glaube ich. Sind dann zwar ein zwei klassen mehrim Projekt, aber so muss ich nix mehr in der GUI-Klasse invoken wenn ich's richtig verstanden habe.
    Habe gerade mal etwas mit dem AsyncWorker experimentiert, um das Event damit zu feuern, jedoch nix brauchbares zusammenstellen können... :/
    hmm...ich glaub da ist es wohl doch am einfachsten, ich invoke die Controls alle...
    Denn ich komme ja nicht drumherum etwas in meine GUI-Klasse zu schreiben, damit das auch ohne invoke funktioniert.
    Genau das war aber mein Vorhaben, trotzdem Danke.

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

    Hast du dir denn mein Beispiel angesehen? Darin ist doch alles beschrieben. Ein Event vergügt über das öffentliche Array .GetInvocationList() welches delegates enthält. Jedes dieser delegates verfügt wiederum über das öffenltiche Objekt Target welches man problem los bei bedarf von der Klass die das Event Feuert Invoken kann.

    Der Event

    VB.NET-Quellcode

    1. Public Delegate Sub OnTickEvent(sender As Object, e As CustomEventArgs)
    2. Public Event TickEvent As OnTickEvent
    3. Private Sub FireEventOnUiThread(e As CustomEventArgs)
    4. If TickEvent IsNot Nothing Then
    5. For Each tickEvent As OnTickEvent In TickEvent.GetInvocationList()
    6. If TypeOf tickEvent.Target Is System.Windows.Forms.Control AndAlso DirectCast(tickEvent.Target, System.Windows.Forms.Control).InvokeRequired Then
    7. DirectCast(tickEvent.Target, System.Windows.Forms.Control).Invoke(tickEvent, Me, e)
    8. Else
    9. tickEvent(Me, e)
    10. End If
    11. Next
    12. End If
    13. End Sub

    jo, das kann man auch einfacher haben (und sicherer):

    VB.NET-Quellcode

    1. Private Sub FireEventOnUiThread(e As CustomEventArgs)
    2. Application.OpenForms(0).BeginInvoke(tickEvent, Me, e)
    3. End Sub
    Muss man halt Sorge tragen, dass OpenForms auch wirklich mindestens ein Form enthält. (Sowas macht halt der AsyncWorker)
    Aber bei der InvokationList gibts auch noch Sachen, gegen die man absichern muss.

    Und BeginInvoke ist (fast) immer vorzuziehen.

    Fakiz schrieb:

    Hast du dir denn mein Beispiel angesehen?
    Ja schon, aber auch dort muss ich etwas in meine Form hinzufügen. Ich wollte es ja in meiner Klasse lösen, aber das geht anscheinend nicht.

    Im Endeffekt läuft ja beides quasi auf das selbe drauf hinaus.
    Laut @ErfinderDesRades ist die Variante mit dem AsyncWorker eleganter bzw. "einfacher und sicherer".

    Nix für Ungut @Fakiz, Dein Vorschlag habe ich auch getestet und funktioniert auch soweit.

    Eventuell kann man das mit meinen Events sogar noch besser lösen?!
    Da ich die Klasse in mehreren Projekten verwenden möchte, ist mir die Idee mit den Events gekommen. Gäbe es dazu evtl. eine Alternative?