Question Help Implementing Event from Interface

zimmerma379

New member
Joined
Mar 8, 2010
Messages
2
Programming Experience
3-5
I am having trouble implementing an Event from an Interface in a ClassLibrary.

Here's the scenario:
o I have 2 projects -- a ClassLibrary "CL1" and a Windows Application.
The ClassLibrary:
o Contains a Friend Interface "I1" and a Public Class "C1".
o The Interface defines one Event "E1" and one Property "P1".
o The Class "C1" implements the Interface "I1".
The Windows Application:
o Instantiates the Class "C1" from the ClassLibrary "CL1" and attempts to handle its event "E1".

Problem:
Everything compiles fine. The “C1.P1” property functions just fine in the Windows Application. But the attempt to handle the “C1.E1” event in the Windows Application throws the following exception:
An unhandled exception of type 'System.MethodAccessException' occurred in WindowsApplication.exe
Additional information: E1EventHandler..ctor(System.Object, IntPtr)

If I change the Interface “I1” in the ClassLibrary to be PUBLIC the exception is NOT thrown. But I don’t want to expose the Interface “I1” outside of the ClassLibrary as it is only used within the ClassLibrary project.

My hunch is that the auto-generated “E1EventHandler” method is marked as Friend from the “I1” Interface and therefore it does not have visibility outside the ClassLibrary? I tried messing around with a Delegate in the ClassLibrary but could not get things to work. I’m not well versed in vb.NET Events & Delegates.

Is there anyway to properly use the Interface “I1” to enforce implementation of the “E1” Event by the Class “C1” within the ClassLibrary but without exposing this Interface outside of the ClassLibrary?

Here’s the sample code:

Project #1 (Class Library) "CL1.vbproj":

File I1.vb:
Code:
Friend Interface I1
   Event E1()
   Property P1() As String
End Interface
File C1.vb:
Code:
Public Class C1
   Implements I1

   Public Event E1() Implements I1.E1

   Public Property P1() As String Implements I1.P1
      Get
      End Get
      Set(ByVal Value As String)
      End Set
   End Property
End Class

Project #2 (Windows Application):
Make reference to Project #1 "CL1" above.

File Form1.vb:
Code:
Public Class Form1
   Inherits System.Windows.Forms.Form

   'Windows Form Designer generated code (not shown)

   Dim WithEvents o As New CL1.C1

   Private Sub o_E1() Handles o.E1
   End Sub
End Class
 
Last edited:

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,331
Location
Norway
Programming Experience
10+
zimmerma379 said:
My hunch is that the auto-generated “E1EventHandler” method is marked as Friend from the “I1” Interface and therefore it does not have visibility outside the ClassLibrary?
That is right, perhaps its because your IDE is very old, but VB 2008 show this error:
IDE said:
'Happened' cannot expose the underlying delegate type 'ISome.HappenedEventHandler' of the event it is implementing outside the project through class 'Test'.
So what you can do is to define the event handler delegate yourself:
Code:
Public Delegate Sub HappenedHandler()
and define the events delegate type explicitly:
Code:
Event Happened As HappenedHandler
The most correct approach though, it to use EventHandler Delegate (System), this delegate has the common (sender As Object, e As EventArgs) signature that is used throughout the .Net class library. It is recommended that you follow this pattern when defining events (Event Design). So you get this event definition instead:
Code:
Event Happened As EventHandler
To raise this event:
Code:
RaiseEvent Happened(Me, EventArgs.Empty)
 

zimmerma379

New member
Joined
Mar 8, 2010
Messages
2
Programming Experience
3-5
Thanks for replying JohnH and confirming my suspicion!

Yes, my IDE is old (VS 2003). The newer VS 2008 compile-time message you quoted is definitely more helpful than the more mysterious runtime error I was getting.

Doh! I was almost on to the proper DELEGATE solution yesterday but I didn’t have it quite right. Thanks for getting me to the solution.

So here’s my sample from above, updated with the correct solution:

Project #1 (Class Library) "CL1.vbproj":

File I1.vb:
Code:
[COLOR="Blue"]Public Delegate Sub E1_Delegate()[/COLOR]

Friend Interface I1
   Event E1 [COLOR="Blue"]As E1_Delegate[/COLOR]
   Property P1() As String
End Interface
File C1.vb:
Code:
Public Class C1
   Implements I1

   Public Event E1 [COLOR="Blue"]As E1_Delegate [/COLOR]Implements I1.E1

   Public Property P1() As String Implements I1.P1
      Get
      End Get
      Set(ByVal Value As String)
      End Set
   End Property
End Class

Project #2 (Windows Application):
Make reference to Project #1 "CL1" above.

File Form1.vb:
Code:
Public Class Form1
   Inherits System.Windows.Forms.Form

   'Windows Form Designer generated code (not shown)

   Dim WithEvents o As New CL1.C1

   Private Sub o_E1() Handles o.E1
   End Sub
End Class
 
Last edited:

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,171
Location
Sydney, Australia
Programming Experience
10+
I have to concur with JohnH that you should stick to the pattern used throughout the .NET Framework when defining your own events. That is, if you don't need to pass any data to or from the event handlers then use the existing EventHandler delegate and, if you do need to pass data, use either the generic EventHandler(Of T) delegate or else define your own delegate with an Object parameter and a parameter whose type inherits EventArgs. There's really no reason not to follow the pattern. Follow the blog link in my signature and check out my post on custom events for more info.
 
Top Bottom