Objekt überwachen und aktualisieren falls sich etwas ändert

  • VB.NET

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von Chriis.

    Objekt überwachen und aktualisieren falls sich etwas ändert

    Momentan setze ich ein wenig mit Klasse auseinander.
    Ich habe mir einer klasse erstellt und möchte nun ein aus dieser Klasse erzeugtes Objekt überwachen. Falls sie dort etwas ändert z.B "Objektname.Guthaben" ist nicht mehr "40" sondern " 50
    das dies wahrgenommen wird und z.B in einem Label wo das Guthaben angezeigt wird auch aktualisiert wird.

    Meine Hauptidee wäre dafür eine Sub zu schreiben die ich dann immer wenn sich was ändert aufrufe aber das müsste ich doch für jede variable machen oder?

    Ich blick das gerade nicht ganz.

    Das ist meine Klasse
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class UserProperties
    2. Dim _stufe As Integer = 1
    3. Dim _gender As Integer = 1
    4. Dim _money As Integer = 2000
    5. Dim _minions As Integer = 0
    6. Dim _name As String = "Name"
    7. Dim _wins As Integer = 0
    8. Dim _losts As Integer = 0
    9. Dim _color As Color = Color.Blue
    10. Public Property lvl() As Integer
    11. Get
    12. Return _stufe
    13. End Get
    14. Set(ByVal value As Integer)
    15. _stufe = value
    16. End Set
    17. End Property 'Stufe
    18. Public Property male() As Integer
    19. Get
    20. Return _gender
    21. End Get
    22. Set(ByVal value As Integer)
    23. _gender = value
    24. End Set
    25. End Property 'Gender
    26. Public Property currMoney() As Integer
    27. Get
    28. Return _money
    29. End Get
    30. Set(ByVal value As Integer)
    31. _money = value
    32. End Set
    33. End Property 'Money
    34. Public Property totalMinios() As Integer
    35. Get
    36. Return _minions
    37. End Get
    38. Set(ByVal value As Integer)
    39. _minions = value
    40. End Set
    41. End Property 'Minions
    42. Public Property igName() As String
    43. Get
    44. Return _name
    45. End Get
    46. Set(ByVal value As String)
    47. _name = value
    48. End Set
    49. End Property 'Name
    50. Public Property totalWins() As Integer
    51. Get
    52. Return _wins
    53. End Get
    54. Set(ByVal value As Integer)
    55. _wins = value
    56. End Set
    57. End Property 'Wins
    58. Public Property totalLosts() As Integer
    59. Get
    60. Return _losts
    61. End Get
    62. Set(ByVal value As Integer)
    63. _losts = value
    64. End Set
    65. End Property 'Loses
    66. Public Property currColor() As Color
    67. Get
    68. Return _color
    69. End Get
    70. Set(ByVal value As Color)
    71. _color = value
    72. End Set
    73. End Property 'Color
    74. End Class

    Dann sende, wenn sich die entsprechende Property ändert, ein Event.
    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!
    Hab jetzt mal ein wenig rumgebprobiert

    VB.NET-Quellcode

    1. Public Event PropertyChanged()
    2. Public Property lvl() As Integer
    3. Get
    4. Return _stufe
    5. End Get
    6. Set(ByVal value As Integer)
    7. _stufe = value
    8. RaiseEvent PropertyChanged()
    9. End Set
    10. End Property 'Stufe


    Und dann einfach so oder wie?

    VB.NET-Quellcode

    1. Private Sub change() Handles Me.PropertyChanged
    2. 'Aktualisieren
    3. End Sub
    Hi
    Ereignisse sollte man mit As EventHandler[(Of T)] deklarieren:

    VB.NET-Quellcode

    1. Public Event Event1 As EventHandler
    2. Public Event Event2 As EventHandler(Of MouseEventArgs)

    Der erste Parameter gibt an, was das Event ausgelöst hat, der zweite definiert zusätzliche Argumente, die übergeben werden sollen, wie die Position der Maus, Informationen über die Änderung, sich zwischendurch ggf. ändernde Werte oder eben Kontextinformationen.

    Gruß
    ~blaze~
    Zum Beispiel so:

    VB.NET-Quellcode

    1. Public Class Test
    2. Public Event ValueChanged As EventHandler
    3. Private _value As Integer
    4. Public Property Value As Integer
    5. Get
    6. Return _value
    7. End Get
    8. Set(value As Integer)
    9. _value = value
    10. OnValueChanged(EventArgs.Empty)
    11. End Set
    12. End Property
    13. Protected Overridable Sub OnValueChanged(e As EventArgs)
    14. RaiseEvent ValueChanged(Me, e)
    15. End Sub
    16. End Class

    OnValueChanged definiert man, um einen Aufruf in der Vererbungsfolge zu ermöglichen, sowie das Ereignis kontrolliert zu verschlucken, etc. Alternativ könnte das obige auch so aussehen:

    VB.NET-Quellcode

    1. Public Class ValueChangedEventArgs
    2. Inherits EventArgs
    3. Private _PreviousValue As Integer
    4. Public Property PreviousValue As Integer
    5. Get
    6. Return _value
    7. End Get
    8. Private Set(value As Integer)
    9. _value = value
    10. End Set
    11. End Property
    12. Public Sub New(previousValue As Integer)
    13. Me.PreviousValue = previousValue
    14. End Sub
    15. End Class
    16. Public Class Test
    17. Public Event ValueChanged As EventHandler(Of ValueChangedEventArgs)
    18. Private _value As Integer
    19. Public Property Value As Integer
    20. Get
    21. Return _value
    22. End Get
    23. Set(value As Integer)
    24. Dim previous As Integer = Value
    25. _value = value
    26. OnValueChanged(New ValueChangedEventArgs(previous))
    27. End Set
    28. End Property
    29. Protected Overridable Sub OnValueChanged(e As ValueChangedEventArgs)
    30. RaiseEvent ValueChanged(Me, e)
    31. End Sub
    32. End Class


    Schöne Verwendungsbeispiele sind übrigens z.B. Form.FormClosing, Form.MouseMove, INotifyPropertyChanged.PropertyChanged, Form.Paint und Form.Click.
    Form.FormClosing lässt zu, dass man Cancel setzt, sodass ggf. das Schließen der Form abgebrochen wird.
    Form.MouseMove hält die Änderungen fest, wie bspw. Modifizierer, die sich in der Zeit zwischen Tastendruck und Verarbeitung ändern können.
    INotifyPropertyChanged.PropertyChanged hat eine definierte Semantik, es wird aufgerufen, wenn sich der Wert, der durch den Namen definierte Eigenschaft, ändert. Der Name wird manuell angegeben (siehe Verwendung) und wird häufig für die Datenbindung verwendet.
    Form.Paint erlaubt den Zugriff auf das Zeichenobjekt e.Graphics, sodass man damit arbeiten kann.
    Bei Form.Click nimmt e je nach Ursache des Klicks unterschiedliche EventArgs-Erben an, so z.B. bei einem Mausklick MouseEventArgs.

    Events selber sind eigentlich eine Art Liste an Aufrufern (Delegaten), die aufgerufen werden, sobald das Ereignis ausgelöst wird.

    INotifyPropertyChanged an sich ist eine sehr unschöne Art der Eigenschaftenverwaltung. Es arbeitet indirekt und ist wohl eher rein zu Datenverarbeitungszwecken vorgesehen, da es den Eigenschaftennamen angibt, der indirekt über Reflection zugeordnet werden soll (oder eher entsprechende PropertyDescriptoren), statt eine Semantik zu verwenden, die das Verhalten definiert, wie es im Programmbeispiel von mir der Fall ist. Die Datenverarbeitung ist in einigen Punkten von der Architektur her aber eher unsauber, weil es keinen "lightweight" Descriptor für Properties gibt...

    Gruß
    ~blaze~

    Chriis schrieb:

    Meine Hauptidee wäre dafür eine Sub zu schreiben die ich dann immer wenn sich was ändert aufrufe aber das müsste ich doch für jede variable machen oder?
    Wie artentus schon sagte: Bei Betrachtung deiner Klasse drängt sich dringend auf, dass deine Klasse INotifyPropertyChanged implementieren sollte.
    Das setzt nämlich genau deine Hauptidee um (und die Sub musste nur einmal schreiben), und ist drüberhinaus ein guter Einstieg in die Welt der databinding-getriebenen Programmierung.

    kannste auch mal im ObjectBrowser angugge das Interface, und von dort mit F1 inne Msdn hopfen.
    Du solltest bei der Implementierung des Events in der Property aufpassen, dass Du nicht in StackOverflowExceptions läufst. Würdest Du versuchen, aus dem EventHandler heraus diese Property zu ändern, so ergibt sich eine Endlosschleife. Ich halte es generell für kein schönes Design, aus Properties heraus Events auszulösen. Du hast ohnehin die Kontrolle darüber, wann eine Property geändert wird. Für meine Logik ist ein Ereignis die Folge einer Aktion. Diese Aktionen sind für mein Verständnis eher Methoden oder Funktionen einer Klasse, keine Eigenschaften. Aber gut, muss jeder selber wissen.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Ein PropertyChanged-Event zur Implementierung des INotifyPropertyChanged-Interfaces wird logischerweise aus der Property ausgelöst, deswegen heisstes ja so.

    Hiermal bisserl was ausgearbeitetes

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Public Class UserProperties : Implements INotifyPropertyChanged
    3. #Region "INotifyPropertyChanged"
    4. Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    5. Protected Sub OnPropertyChanged(propName As String)
    6. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
    7. End Sub
    8. Protected Function SetProperty(Of T)(ByRef backingField As T, value As T, propName As String) As Boolean
    9. If Object.Equals(backingField, value) Then Return False
    10. backingField = value
    11. OnPropertyChanged(propName)
    12. Return True
    13. End Function
    14. #End Region 'INotifyPropertyChanged
    15. Dim _stufe As Integer = 1
    16. Dim _gender As Integer = 1
    17. Dim _money As Integer = 2000
    18. Dim _minions As Integer = 0
    19. Dim _name As String = "Name"
    20. Dim _wins As Integer = 0
    21. Dim _TotalLosts As Integer = 0
    22. Dim _color As Color = Color.Blue
    23. Public Property Lvl() As Integer
    24. Get
    25. Return _stufe
    26. End Get
    27. Set(ByVal value As Integer)
    28. SetProperty(_stufe, value, "Lvl")
    29. End Set
    30. End Property 'Stufe
    31. Public Property Male() As Integer
    32. Get
    33. Return _gender
    34. End Get
    35. Set(ByVal value As Integer)
    36. SetProperty(_gender, value, "Male")
    37. End Set
    38. End Property 'Gender
    39. Public Property CurrMoney() As Integer
    40. Get
    41. Return _money
    42. End Get
    43. Set(ByVal value As Integer)
    44. SetProperty(_money, value, "CurrMoney")
    45. End Set
    46. End Property 'Money
    47. Public Property TotalMinios() As Integer
    48. Get
    49. Return _minions
    50. End Get
    51. Set(ByVal value As Integer)
    52. SetProperty(_minions, value, "TotalMinios")
    53. End Set
    54. End Property 'Minions
    55. Public Property IgName() As String
    56. Get
    57. Return _name
    58. End Get
    59. Set(ByVal value As String)
    60. SetProperty(_name, value, "IgName")
    61. End Set
    62. End Property 'Name
    63. Public Property TotalWins() As Integer
    64. Get
    65. Return _wins
    66. End Get
    67. Set(ByVal value As Integer)
    68. SetProperty(_wins, value, "TotalWins")
    69. End Set
    70. End Property 'Wins
    71. Public Property TotalLosts() As Integer
    72. Get
    73. Return _TotalLosts
    74. End Get
    75. Set(ByVal value As Integer)
    76. SetProperty(_TotalLosts, value, "TotalLosts")
    77. End Set
    78. End Property 'Loses
    79. Public Property CurrColor() As Color
    80. Get
    81. Return _color
    82. End Get
    83. Set(ByVal value As Color)
    84. SetProperty(_color, value, "CurrColor")
    85. End Set
    86. End Property 'Color
    87. End Class

    @TE: zu deine Benamung:
    1. Public classmember immer groß schreiben
    2. BackingFields sollten ihrer Public Property namentlich entsprechen (etwa _TotalLosts <-> TotalLosts)
    @SpaceXY Das Event ändert ja nicht die Property sondern nur eine Variable. Sprich durch das Event wird das Event nicht noch einmal aufgerufen.

    @EDR Ungefähr genau das habe ich die ganze Zeit versucht :) Vielen Dank. Und ausnahmsweise habe ich es direkt verstanden dank dir.
    Echt? alles verstanden?
    Auch das mit dem Interface? Und dass die SetProperty-Sub erst testet, ob der neue Wert auch neu ist, bevor das Event geraist wird? Und warum OnPropertyChanged und SetProperty beide Protected sind, und nicht Public oder Private?
    Und der Typ-Parameter von SetProperty? nö - kauf ich dir nicht ab.

    jedenfallse wie gesagt: Deine Klasse stellt einen typischen Datensatz dar.
    Für Datensätze gibts enorm leistungsfähige Standard-Klassen, und Kernkonzept solcher Datenverarbeitung ist Databinding.
    Und Grundlage von Databinding ist das INotifyPropertyChanged-Interface, was von Datenklassen zu implementieren ist, damit die anneren Technologien ühaupt greifen können.
    Wohin dich das führen kann ist in vier Views-Videos kurz angerissen.

    Vmtl. bist du noch nicht so weit, aber du scheinst mir doch auf dem Weg dahin, denn offensichtlich hast du nach INotifyPropertyChanged gesucht. :thumbsup:
    Ist ja gut :D. Sagen wir mal so: Ich habe es im groben verstanden. ...groooben. Ich gönn mir jetzt erstmal einen Kaffee und dann schau ich mir das alles noch mal an.
    Einen Teil ( sagen wir 45%) habe ich wirklich verstanden. Den Rest versuch ich sobald ich meinen Kaffee getrunken habe zu verstehen.