views:

245

answers:

3

Hello, I am looking at this blog, and I am trying to translate the snippet to VB.

I'm having difficulties with this line:

NotifyCollectionChangedEventHandler handlers = this.CollectionChanged;

NOTE: CollectionChanged is an event of this ('this' is an override of ObservableCollection<T>).

+2  A: 

Literally, it should be something like

Dim handlers As NotifyCollectionChangedEventHandler = AddressOf Me.CollectionChanged

(can't tell since I don't know the exact types)

But note that you raise events in VB using RaiseEvent

Dario
This only works if `CollectionChanged` is the subscriber, not the event handler (which it probably is) but in this case, your second sentence applies.
Konrad Rudolph
It doesn't work at all, I tried this a year ago. AddressOf expects nothing but a method name.
Shimmy
@Shimmy: given your information, it was a valid guess. `AddressOf` works in this exact context. There’s no other direct translation of what you want.
Konrad Rudolph
OK, Please review the post in that blog.
Shimmy
+2  A: 

Duh. After having finally seen and read the blog posting you linked, here’s the answer:

In VB, you need to declare a custom event to override the RaiseEvent mechanism. In the simplest case, this looks like this:

Private m_MyEvent As EventHandler

Public Custom Event MyEvent As EventHandler
   AddHandler(ByVal value as EventHandler)
      m_MyEvent = [Delegate].Combine(m_MyEvent, value)
   End AddHandler

   RemoveHandler(ByVal value as EventHandler)
      m_MyEvent = [Delegate].Remove(m_MyEvent, value)
   End RemoveHandler
   RaiseEvent(sender as Object, e as EventArgs)
      Dim handler = m_MyEvent

      If handler IsNot Nothing Then
          handler(sender, e)
      End If
   End RaiseEvent
End Event

In your case, the RaiseEvent routine is slightly more involved to reflect the additional logic, but the gist remains the same.

Konrad Rudolph
@Shimmy: I rolled back your edit; it actually introduced a nasty multithreading bug. Copying the event handler **is** important! (And `Shadows` just had no place in there.)
Konrad Rudolph
how can i get in to the base event then?
Shimmy
@Shimmy: you cannot. For whatever reason, no class can access its base class events directly. .NET just doesn’t allow that.
Konrad Rudolph
but if use the custom even it doesn't do anything, since the events are attached to the INotifyCollectionChanged event ignoring the custom event
Shimmy
+2  A: 

To raise the event, OnCollectionChanged should work fine. If you want to query it you have to get more abusive and use reflection (sorry, example is C# but should be virtually identical - I'm not using any language-specific features here):

NotifyCollectionChangedEventHandler handler = (NotifyCollectionChangedEventHandler)
    typeof(ObservableCollection<T>)
    .GetField("CollectionChanged", BindingFlags.Instance | BindingFlags.NonPublic)
    .GetValue(this);

et voila; the handler or handlers (via GetInvocationList()).

So basically in your example (regarding that post), use:

Protected Overrides Sub OnCollectionChanged(e As NotifyCollectionChangedEventArgs)
    If e.Action = NotifyCollectionChangedAction.Add AndAlso e.NewItems.Count > 1 Then
        Dim handler As NotifyCollectionChangedEventHandler = GetType(ObservableCollection(Of T)).GetField("CollectionChanged", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(Me)
        For Each invocation In handler.GetInvocationList
            If TypeOf invocation.Target Is ICollectionView Then
                DirectCast(invocation.Target, ICollectionView).Refresh()
            Else
                MyBase.OnCollectionChanged(e)
            End If
        Next
    Else
        MyBase.OnCollectionChanged(e)
    End If
End Sub
Marc Gravell
@Mark, you're the winner, big time!
Shimmy