views:

56

answers:

3

I am attempting to share a sub menu among several different parts of an application so that it is consistent (not wanting to copy/paste.) I thought it would be simple. I am doing something like this:

 public class MyClientClass
     Private WithEvents ctx As ContextMenuManager = New ContextMenuManager
     Private Sub handler() Handles ctx._myToolstripMenuItem.Click
         ' do something useful
    End Sub
End Class

Public Class ContextMenuManager
    Public WithEvents _myToolstripMenuItem As ToolStripMenuItem

    Public Sub New()
        Me._myToolstripMenuItem = New ToolStripMenuItem
        Me._myToolstripMenuItem.Name = "DoSomehting"
        Me._myToolstripMenuItem.Size = New System.Drawing.Size(48, 20)
        Me._myToolstripMenuItem.Text = "Go!"
    End Sub
End Class

But that code gives me an Error: 'Handles' in classes must specify a 'WithEvents' variable, 'MyBase', 'MyClass' or 'Me' qualified with a single identifier.

I supplied the WithEvents keyword for both the container app and the menu item. What gives? What am I missing? Would a C# example give the same error?

Changed focus to solve this another way. Handling all events in the shared class and firing a common event with a common obj:

Private Sub MenuItem_Click(ByVal sender As Object, ByVal e As EventArgs) _
 Handles ToolStripMenuItem.Click
     ' edit _legacyAttributes instance per specifics
     ' ...
     ' then always raise the same event with the updated payload object
     RaiseEvent TypeChanged(_legacyAttributes)
 End Sub

So, you can imagine that there are dozens of handlers like this in the class, each one modifying its _legacyAttributes as it makes sense...

A: 

Can't find the answer as to why the Handles syntax isn't working but I did find an OK workaround using the AddHandler to attach events. So instead of:

Handles ctx._myToolstripMenuItem.Click

In a load event or some initial method I will do:

AddHandler ctx._myToolstripMenuItem.Click, AddressOf handlerMethod
Paul Sasik
+1  A: 

The extra indirection is not allowed. You'd have to write the ContextMenuManager class like this:

Public Class ContextMenuManager
    Public Event Click As EventHandler
    Private WithEvents _myToolstripMenuItem As ToolStripMenuItem

    Public Sub New()
        ''...
    End Sub

    Private Sub _myToolstripMenuItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _myToolstripMenuItem.Click
        RaiseEvent Click(Me, e)
    End Sub
End Class

Now you can use "Handles _ctx.Click". There's certainly value in hiding the implementation details of ContextMenuManager so the extra code may well be worth it. Yes, AddHandler doesn't have this restriction.

Hans Passant
I'm curious. Did you add the event?
Hans Passant
Marking yours rather than mine as the answer since i ended with a solution that's close to this one. Only difference was that i routed all events into a single call where i raised a common event and pass an info class... saved from having to rewire and duplicate all the evts. Thx nbgz.
Paul Sasik
+1  A: 

A "withevents" declaration is a very nice bit of syntactic sugar which is something like this:

WithEvents Foo as Control 
  -- becomes
Dim _Foo as Control
Property Foo as Control
  Get
    Return _Foo
  End Get
  Set(Value as Control)
    If _Foo IsNot Nothing Then
      RemoveHandler _foo.Click,foo_Click
      RemoveHandler _foo.Load,foo_Load
      etc.
    End If
    _Foo = Value
    If _Foo IsNot Nothing Then
      AddHandler _foo.Click,foo_Click
      AddHandler _foo.Load,foo_Load
      etc.
    End If
  End Set
End Property

There will be one RemoveHandler and one AddHandler for each Handles declaration associated with Foo. Note that such property declarations can only be done within the present class. There is no general way for a class to tell another class that setting one of its properties should cause events to be subscribed on the former class's behalf.

supercat