views:

86

answers:

3

What is the optimal approach to a WithEvents Collection - VB.NET?

Have you any remarks on the code bellow (skipping the Nothing verifications)?

The problem is when I obtain the LinkedListNode(Of Foo) in a For Each block I can set myNode.Value = something, and here is a handlers leak...

-Could I override the FooCollection's GetEnumerator in this case?
-No. :( cause NotInheritable Class LinkedListNode(Of T)

Class Foo
  Public Event SelectedChanged As EventHandler
End Class

Class FooCollection
  Inherits LinkedList(Of Foo)
  Public Event SelectedChanged As EventHandler

  Protected Overloads Sub AddFirst(ByVal item As Foo)
    AddHandler item.SelectedChanged, AddressOf OnSelectedChanged
    MyBase.AddFirst(item)
  End Sub

  Protected Overloads Sub AddLast(ByVal item As Foo)
    AddHandler item.SelectedChanged, AddressOf OnSelectedChanged
    MyBase.AddLast(item)
  End Sub

  ' ------------------- '

  Protected Overloads Sub RemoveFirst()
    RemoveHandler MyBase.First.Value.SelectedChanged, _
                         AddressOf OnSelectedChanged
    MyBase.RemoveFirst()
  End Sub

  Protected Overloads Sub RemoveLast(ByVal item As Foo)
    RemoveHandler MyBase.Last.Value.SelectedChanged, _
                        AddressOf OnSelectedChanged
    MyBase.RemoveLast()
  End Sub

  ' ------------------- '

  Protected Sub OnSelectedChanged(ByVal sender As Object, ByVal e As EventArgs)
    RaiseEvent SelectedChanged(sender, e)
  End Sub
End Class
A: 

As I understand, there is no easy solution because the collection just holds references to the ocjects and has therefore no way to know, if a property of an object the collection holds has changed.

In general you have to options:

1:) You let the objects your collection controls fire events. A sample implementation you find in this MSDN article from Charles Petzold. He defines a "ObservableNotifiableCollection".

2:) If the types the collection holds are not at your control (so you can't implement a PropertyChangedEvent yourself), you could use a proxy objects. A sample implementation you can find here: "Implement InotifyPropertyChanged with Castle.DynamicProxy".

Robert
A: 

The main problem is that you can't override the GetEnumerator function properly. In such case I would create a class that doesn't directly inherit from LinkedList but only uses one as a private field:

Class FooCollection
    Implements ICollection(Of Foo)

    Private list As New LinkedList(Of Foo)

    Public Sub AddFirst(ByVal item As Foo)
        AddHandler item.SelectedChanged, AddressOf OnSelectedChanged
        list.AddFisrt(item)
    End Sub

    ...

End Class

It will require a little more coding because you need to implement all the functions instead of just the ones you want to override but the implementation is trivial.

Bus
+1  A: 

Have you looked at CollectionChangedEventManager? I just ran across this today when looking to deal with queue changes.

AMissico