Event aus untergestelltem Objekt behandeln

  • VB.NET

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

    Event aus untergestelltem Objekt behandeln

    Hallo,
    ich habe aktuell das Problem, dass ich auf die Änderung eines Wertes in einer (Unter-)Klasse reagieren will. Mir fällt leider aktuell nur keine saubere Struktur, mit der ich das Problem lösen kann, ein. Bei der Verschachtelung der Klassen ist es leider mit einem Event nicht getan.

    Meine beiden Lösungsansätze wären die Datenstruktur zu ändern, aber die bekomme ich von außen per JSON und sie wird dann direkt in die Klassenstruktur umgesetzt. Des Weiteren kann ich mir noch eine Eventkette vorstellen, bei der ein Event ein anderes auslöst, bis ich an der gewünschten Position angekommen bin. Von den Ideen bin ich bisher noch nicht ganz überzeugt. Habt ihr einen besseren Ansatz?

    Habe meine Klassenstruktur mal stark vereinfacht dargestellt:

    VB.NET-Quellcode

    1. Class Hauptsammlung
    2. Dim WithEvents Daten As New Nebensammlung
    3. Sub ReaktionWert1() 'Soll auf Änderung von Wert1 reagieren
    4. End Sub
    5. End Class
    6. Public Class Nebensammlung
    7. Public Werte As New Wertesammlung 'davon gibt es 5-6 Stück im eigentlichen Programm
    8. End Class
    9. Public Class Wertesammlung
    10. Public Werte As New Wert 'davon etwa 7-8 Stück im eigentlichen Programm
    11. End Class
    12. Public Class Wert
    13. Private _Wert1 As Integer 'etwa 30 Werte im eigentlichen Programm
    14. Public Property Wert1 As Integer
    15. Get
    16. Wert1 = _Wert1
    17. End Get
    18. Set(value As Integer)
    19. If True Then
    20. _Wert1 = value 'Hier soll das Event aufgerufen werden
    21. End If
    22. End Set
    23. End Property
    24. End Class


    Liebe Grüße
    K4RTOFF3L
    Gruß K4RTOFF3L

    Das Problem zu erkennen ist wichtiger, als die Lösung zu erkennen, denn die genaue Darstellung des Problems führt zur Lösung. - Albert Einstein
    Ein Event wird nicht aufgerufen, sondern abgefeuert/gesendet/"geraised". Ein EventHandler empfängt es. Da Du kein RaiseEvent im Property-Setter nutzt und auch keinen EventHandler formuliert hast, passiert auch nichts.

    <Eigenwerbung>
    Saubere(re) Strukturen und Trennung habe ich neulich hier mal angefangen, aufzulisten.
    WinForms Projektentwicklung bzgl. der Rolle des Formulars
    </Eigenwerbung>
    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.
    Vielen Dank für deine Antwort. Das war mir bewusst, jedoch habe ich das Problem, dass ich höchstens eine Ebene weiter nach unten kann. Also Hauptsammlung kann nur auf Events von Nebensammlung zugreifen, aber nicht mehr auf Events von Wertesammlung und dies selbst wenn es bis auf die unterste Ebene hindurch als "WithEvents" gekennzeichnet ist. Sowas wie Sub ReaktionWert1() Handles Daten.Werte.Werte.testevent ist nicht möglich. Ich habe wohl ein bisschen zu viel gekürzt um den Raum für mehr Vorschläge zu erweitern.
    Gruß K4RTOFF3L

    Das Problem zu erkennen ist wichtiger, als die Lösung zu erkennen, denn die genaue Darstellung des Problems führt zur Lösung. - Albert Einstein

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

    Du hast recht, dass das nicht geht. Du kannst aber schreiben:
    AddHandler Daten.Hauptstruktur.testevent, AddressOf DeineSub
    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.

    K4RTOFF3L schrieb:

    dass ich höchstens eine Ebene weiter nach unten kann.
    In diesem Falle musst Du das Event sich durchhangeln lassen bis dahin, wo es ankommen soll.
    Nutze dieselben EventArgs, dann musst Du in den betreffenden EventHandlern nur noch RaiseEvent aufrufen und feddich.
    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!
    Ich würde als Event das PropertyChangedEvent von INotifyPropertyChanged empfehlen. Im von Vaporized verlinkten Tut habich da auch ein Sample gebastelt, wo das vorkommt.
    Vorteil wäre, du musst nur ein Event deklarieren, und nur einen Eventhandler schreiben.
    Im Eventhandler musste dann aber die Objekte und Properties auseinanderklamüsern, die das Event jeweils gefeuert haben.

    Eventuell - wenn du nicht viel mehr tun willst, als die Werte anzuzeigen - kannste ja auch Databinding benutzen. Dann brauchste nichtmal eine Eventhandler-Methode.

    Allerdings bin ich gespannt, ob die Funktion der Tutorial-Projekte verständlich genug dargestellt ist.
    Wir (Vaporized und ich) zeigen da nämlich nicht, wie wir mit dem Datenquellfenster ObjektDatenquellen generiert haben, um daran zu binden.

    Also wie immer: Bei Fragen nicht wegzappen, sondern fragen.
    Hallo,
    ich habe eure Ansätze jetzt umgesetzt, jedoch habe ich ein Problem die Änderung in meine Form zu bekommen. Aktuell bin ich noch bei der Version von VaporiZed, aber würde, sobald das Problem gelöst ist, auf die Idee von ErfinderDesRades mit INotifyPropertyChanged wechseln.

    Meine Daten bekomme ich aus einer JSON, die im lokalen Netz liegt und von mir heruntergeladen wird. Dieser Vorgang, ebenso wie die Deserialisierung, passiert in einem Tick-Event eines Timers. Hierbei tritt defintiv kein Fehler auf. Wenn ich jetzt auf die Feuerung meines Events warte, dann passiert diese nicht, solange die Daten durch den Timer zugewiesen werden. Wenn ich jedoch einen Wert über z.B. einen Butten ändere, dann wird das Event gefeuert und ich kann auf den neuen Wert reagieren. Wieso ist dies so und wie löst man dieses Problem? Habe am Anfang gedacht, dass es daran liegt, dass der "normale" Timer der Grund ist und bin auf den System.Threading.Timer umgestiegen, aber ohne Erfolg.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim stateTimer As System.Threading.Timer
    3. Public WithEvents DataToSend As New Data
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. AddHandler DataToSend.Daten1.valueChanged, AddressOf test
    6. End Sub
    7. Sub test()
    8. MsgBox("Wert geändert")
    9. End Sub
    10. Private Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
    11. stateTimer = New Threading.Timer(AddressOf T_Tick, Nothing, 0, 5000)
    12. End Sub
    13. Private Sub T_Tick(state As Object)
    14. Dim web As New WebClient
    15. DataToSend = JsonConvert.DeserializeObject(Of Data)(Web.DownloadString("http://" + TextBox1.Text))
    16. End Sub
    17. End Class


    VB.NET-Quellcode

    1. Public Class Data
    2. Public WithEvents Daten1 As New Daten_1
    3. End Class
    4. Public Class Daten_1
    5. Public Event valueChanged()
    6. Private _Wert1 As Boolean
    7. Public Property Wert1 As Boolean
    8. Get
    9. Wert1 = _Wert1
    10. End Get
    11. Set(value As Boolean)
    12. _Wert1 = value
    13. RaiseEvent valueChanged()
    14. End Set
    15. End Property
    16. End Class


    Edit:
    Habe die Informationen hinzugefügt, @VaporiZed
    Gruß K4RTOFF3L

    Das Problem zu erkennen ist wichtiger, als die Lösung zu erkennen, denn die genaue Darstellung des Problems führt zur Lösung. - Albert Einstein

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „K4RTOFF3L“ ()

    Wo wird der Timer initialisiert und gestartet (beides geschieht nicht in Zeile#2!) ? Wie ist Data definiert? Wie erfasst Data seine eigenen Änderungen? In Z#16 wird DataToSend neu belegt. Das ist keine Wertänderung, die ein Objekt selbst erfassen kann (zumindest ist mir da nix bekannt)!

    @K4RTOFF3L: Genau. Da nicht ein Wert von DataToSend geändert wird, sondern DataToSend selbst, wird Codeblock#2, Zeile#16 (RaiseEvent valueChanged()) nicht 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.

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

    Jo - das ist die K*** mit dem Serialisier-Fimmel.
    Serialisieren erzeugt immer ein neue Objekt. Da nütztes dann nicht, wenn vom alten Objekt ein Event abonniert ist.

    Aber bei sonem "vereinfachten" Klassensystem kann man auch nicht wirklich weiterhelfen - inne Realität sieht's dann doch wieder ganz anners aus.

    Warum geht nicht einfach

    VB.NET-Quellcode

    1. Private Sub T_Tick(state As Object)
    2. Dim web As New WebClient
    3. DataToSend = JsonConvert.DeserializeObject(Of Data)(Web.DownloadString("http://" + TextBox1.Text))
    4. test()
    5. End Sub
    Damit würde test ebenso aufgerufen, wenn der timer getickt hat.
    Das habe ich mir bereits befürchtet. Das Problem besteht halt darin, dass ich die Werte seriell an eine Schnittstelle weiterleiten muss und dort nicht einfach auf gut Glück alle Werte übertragen kann/möchte, sondern erst bei einer bestimmten Änderungen des Wertes.

    Die Verarbeitung der Daten und das feuern des Events bei Bedarf habe ich jetzt realisiert. Meiner Meinung war es der einfachste Weg ein zweites Objekt zu erstellen und dieses ersetzen zu lassen durch den Serialisier. Anschließend die Werte des zweiten Objektes an das erste Objekt zu übertragen. Hierbei entsteht jetzt das nächste Problem, da ich meinen Ansatz zum Übertragen nicht sinnvoll finde. Aktuell ist es die Aufgabe der Methode "test" aus dem Beispiel von EdR die Werte in der Form Daten_1.wert1 = Daten_2.wert1 zu übertragen, jedoch bin ich mir sicher, dass es dafür eine bessere Lösung geben muss, die auch ein bisschen Wartungsfreundlicher ist. Bei meiner Recherche fand ich die Möglichkeit Dim info() As PropertyInfo = Daten_2.GetType().GetProperties(), aber bei der Übertragung der Werte scheitert es dann bei mir, da der Ansatz fehlt. Es wird zusätzlich von diesem Ansatz abgeraten, da es nicht sonderlich performant sein soll. Ebenso scheitere ich an der Implementierung von IEnumerator für Propertys und wollte wissen welcher der beiden Wege der "bessere" ist, vielleicht habt ihr auch eine weitere Idee, bevor ich mich mit der Behebung der Fehler beschäftige.
    Gruß K4RTOFF3L

    Das Problem zu erkennen ist wichtiger, als die Lösung zu erkennen, denn die genaue Darstellung des Problems führt zur Lösung. - Albert Einstein

    K4RTOFF3L schrieb:

    vielleicht habt ihr auch eine weitere Idee
    Oh - ich habe andauernd weitere Ideen - aber ich glaube nicht, dass du die alle wissen willst.
    Zu deinen beiden Wegen habich nur die Idee, dass ich mal deren Code sehen müsste.
    Aber das sagte ich ja schon, und das ignorierst du ja mit Fleiss.