auf List(of).add reagieren

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von KingTimon.

    auf List(of).add reagieren

    Sehr geehrte Community,

    mir hat sich gerade eine interessante Frage gestellt.

    Ich habe eine Property, die sieht folgendermaßen aus:

    VB.NET-Quellcode

    1. ​Public Property [Elements] As New List(Of FileComponents.Element)

    Diese Elemente sind dann für das Zeichnen eines Controls zuständig, daher benötigt mein Control ein .Invalidate, sobald der Liste ein Element zugefügt oder entfernt wurde.

    Ich hab schon probiert, ob "Public WithEvents" bei einer List(of ) funktioniert - leider erfolglos. Und mmn reicht es auch nicht, ein Get/Set hinzuzufügen, da die Liste ja die gleiche bleibt und nur verändert wird...

    Wie würdet ihr hier vorgehen? Wie kann ich ein Event auslösen, sobald ein Element geaddet/entfernt wurde?

    Soll ich mit einer eigenen Funktion anstatt mit Elements.add arbeiten?

    Mit freundlichen Grüßen
    Auf der Suche nach Coding-Kursen auf Lence.at
    Nur dass die Events der ObservableCollection äußerst unhandlich zu handhaben sind. Und leider gibts auch ein paar Tücken, wenn man z.B. an der Liste die Clear-Methode aufruft, denn man hat keine Möglichkeit, an die entfernten Items heranzukommen.
    Deshalb hab ich eine Hilfs-Klasse für den Kram geschrieben:

    VB.NET-Quellcode

    1. Public Class ItemEventArgs(Of T)
    2. Inherits EventArgs
    3. Dim _Item As T
    4. Public ReadOnly Property Item As T
    5. Get
    6. Return _Item
    7. End Get
    8. End Property
    9. Public Sub New(NewItem As T)
    10. _Item = NewItem
    11. End Sub
    12. End Class
    13. Public Class TypedObservableCollection(Of T)
    14. Inherits System.Collections.ObjectModel.ObservableCollection(Of T)
    15. 'Wird ausgelöst, wenn ein Element hinzugefügt wurde.
    16. Public Event ItemAdded As EventHandler(Of ItemEventArgs(Of T))
    17. Protected Overridable Sub OnItemAdded(Item As T)
    18. RaiseEvent ItemAdded(Me, New ItemEventArgs(Of T)(Item))
    19. End Sub
    20. 'Wird ausgelöst, wenn ein Element entfernt wurde.
    21. Public Event ItemRemoved As EventHandler(Of ItemEventArgs(Of T))
    22. Protected Overridable Sub OnItemRemoved(Item As T)
    23. RaiseEvent ItemRemoved(Me, New ItemEventArgs(Of T)(Item))
    24. End Sub
    25. 'Wird ausgelöst, wenn sich die Liste verändert hat.
    26. Public Event TypedCollectionChanged As EventHandler
    27. Protected Overridable Sub OnTypedCollectionChanged()
    28. RaiseEvent TypedCollectionChanged(Me, EventArgs.Empty)
    29. End Sub
    30. 'Die Implementierung in der ObservableCollection-Klasse sieht so aus.
    31. Protected Overrides Sub ClearItems()
    32. CheckReentrancy()
    33. MyBase.ClearItems()
    34. OnPropertyChanged("Count")
    35. OnPropertyChanged("Item[]")
    36. OnCollectionReset() 'Hier wird nur das CollectionChanged-Event mit Action=Reset ausgelöst.
    37. End Sub
    38. 'Hier wird zusätzlich das ItemRemoved-Event für jedes Element ausgelöst.
    39. Protected NotOverridable Overrides Sub ClearItems()
    40. CheckReentrancy()
    41. Dim OldItems = Items.ToArray 'Kopie
    42. MyBase.ClearItems() 'Überschriebene Methode ausführen, damit die Elemente wirklich gelöscht werden und die bestehenden Events korrekt ausgelöst werden.
    43. 'Eigene Events auslösen
    44. For Each In OldItems
    45. OnItemRemoved(i)
    46. Next
    47. OnTypedCollectionChanged()
    48. End Sub
    49. 'Hier werden die meisten Fälle abgedeckt.
    50. Protected Overrides Sub OnCollectionChanged(e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
    51. MyBase.OnCollectionChanged(e)
    52. Select Case e.Action
    53. Case Specialized.NotifyCollectionChangedAction.Add
    54. For Each i As T In e.NewItems
    55. OnItemAdded(i)
    56. Next
    57. OnTypedCollectionChanged()
    58. Case Specialized.NotifyCollectionChangedAction.Remove
    59. For Each i As T In e.OldItems
    60. OnItemRemoved(i)
    61. Next
    62. OnTypedCollectionChanged()
    63. Case Specialized.NotifyCollectionChangedAction.Replace
    64. If Not e.NewItems.Count = e.OldItems.Count Then
    65. 'Sollte eigentlich nie passieren, aber für den Fall, dass sich irgendwo ein Bug eingeschlichen hat, wird man dadurch drauf aufmerksam.
    66. Throw New NopeException("Beim Ersetzen muss die Anzahl an entfernten Elementen gleich der Anzahl an hinzugefügten Elementen sein.")
    67. End If
    68. For Each i As T In e.OldItems
    69. OnItemRemoved(i)
    70. Next
    71. For Each i As T In e.NewItems
    72. OnItemAdded(i)
    73. Next
    74. OnTypedCollectionChanged()
    75. Case Specialized.NotifyCollectionChangedAction.Reset
    76. OnTypedCollectionChanged()
    77. Case Specialized.NotifyCollectionChangedAction.Move
    78. 'Bei Move sollten keine Elemente entfernt oder hinzugefügt worden sein.
    79. OnTypedCollectionChanged()
    80. End Select
    81. End Sub
    82. End Class


    Ein ganz simples Verwendungsbeispiel würde dann so aussehen:

    VB.NET-Quellcode

    1. Public Class CustomControl
    2. Public Event Invalidated()
    3. Protected Overridable Sub OnInvalidated()
    4. RaiseEvent Invalidated()
    5. End Sub
    6. Public Property Owner As CustomControl = Nothing
    7. Dim WithEvents _Children As New TypedObservableCollection(Of CustomControl)
    8. Public ReadOnly Property Children As TypedObservableCollection(Of CustomControl)
    9. Get
    10. Return _Children
    11. End Get
    12. End Property
    13. Private Sub Children_ItemAdded(sender As Object, e As ItemEventArgs(Of CustomControl)) Handles _Children.ItemAdded
    14. e.Item.Owner = Me
    15. AddHandler e.Item.Invalidated, AddressOf OnInvalidated
    16. End Sub
    17. Private Sub Children_ItemRemoved(sender As Object, e As ItemEventArgs(Of CustomControl)) Handles _Children.ItemRemoved
    18. e.Item.Owner = Nothing
    19. RemoveHandler e.Item.Invalidated, AddressOf OnInvalidated
    20. End Sub
    21. Private Sub Children_TypedCollectionChanged(sender As Object, e As EventArgs) Handles _Children.TypedCollectionChanged
    22. 'Da fällt mir jetzt gerade kein Beispiel ein.
    23. End Sub
    24. End Class

    Man muss sich um nichts mehr kümmern.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Vielen Dank @Counterbug und @Niko Ortner für eure Hilfe!
    Im Prinzip benötige ich die Funktion nur dazu, ein Control zu Invalidaten, daher danke für den Tipp mit ObservableCollection<t>.
    Auf der Suche nach Coding-Kursen auf Lence.at