views:

163

answers:

4

I am writing a Class Library that will be used by other applications. I am writing it in C#.NET. I am having a problem with triggering events across classes. Here is what I need to do...

public class ClassLibrary
{
    public event EventHandler DeviceAttached;

    public ClassLibrary()
    {
        // do some stuff
        OtherClass.Start();
    }
}

public class OtherClass : Form
{
    public Start()
    {
        // do things here to initialize receiving messages
    }

    protected override void WndProc (ref message m)
    {
       if (....)
       {
          // THIS IS WHERE I WANT TO TRIGGER THE DEVICE ATTACHED EVENT IN ClassLibrary
          // I can't seem to access the eventhandler here to trigger it.
          // How do I do it?

       }
       base.WndProc(ref m);
    }

}

Then in the application that is using the class library I will do this...

public class ClientApplication
{
    void main()
    {
       ClassLibrary myCL = new ClassLibrary();
       myCL.DeviceAttached += new EventHandler(myCl_deviceAttached);
    }

    void myCl_deviceAttached(object sender, EventArgs e)
    {
         //do stuff...
    }
}
+7  A: 

You cannot do this. Events can only be raised from within the class that declares the event.

Typically, you'd add a method on your class to raise the event, and call the method:

public class ClassLibrary 
{ 
    public event EventHandler DeviceAttached; 
    public void NotifyDeviceAttached()
    {
       // Do processing and raise event
     }

Then, in your other code, you'd just call myCL.NotifyDeviceAttached();

Reed Copsey
Does NotifyDeviceAttached need to be static? Otherwise how do I reference the instance of ClassLibrary from OtherClass when OtherClass did not create it?
Jordan S
You'll need to supply your form with a proper instance. Otherwise, you can make NotifyDeviceAttached static, but then you'll also need to make your event handler a static event, too... It's all a matter of design.
Reed Copsey
+1  A: 

Event handlers can only be called directly by the class that declared them. If you need to call ClassLibrary.DeviceAttached from outside that class, you need to add a utility method like the following:

public void OnDeviceAttached()
{
    DeviceAttached();
}
JSBangs
hmmm ok. Can the event be passed to the class as a reference and called that way?
Jordan S
@Jordan S: No. The C# designers purposely made it so that you can't raise an event from another class, even a subclass. You MUST do it from the class that declared the event.
Reed Copsey
Does OnDeviceAttached need to be static? Otherwise how do I reference the instance of ClassLibrary from OtherClass when OtherClass did not create it?
Jordan S
+1  A: 

You may not want to use an event at all here. This is an oversimplification, but generally an event is something raised by a child component when it needs to communicate something back to its parent. In your case (I'm inferring from your code) your form is listening for a specific message (when a device is attached?), and when it spots that message it needs to tell myCL about it. For this purpose, you would instead just create a method in ClassLibrary and call it from your form.

MusiGenesis
My example leaves out a lot of details. OtherClass is not actually a visible form, it just inherits from Form so that it can be used to catch the Windows messages when USB device are attached/received... I know it's confusing.
Jordan S
+1  A: 

I think you should change your perspective on how events work. OtherClass should "own" the event and trigger it. ClassLibrary or ClientApplication (whichever you choose) "listens" to the event by "subscribing" to it and does a certain action when this event occurs.

How to implement this:

public class ClassLibrary
{
    public OtherClass myOtherCl;

    public ClassLibrary()
    {
        myOtherCl= new OtherClass();
        myOtherCl.Start();
    }
}

Trigger the event in the class where it logically happens, where it is detected.

public class OtherClass : Form { public event EventHandler DeviceAttached;

public Start()
{
    // do things here to initialize receiving messages
}

protected override void WndProc (ref message m)
{
   if (....)
   {
      OnDeviceAttach();
   }
   base.WndProc(ref m);
}

    public void OnDeviceAttach()
    {
        if (DeviceAttached != null)
            DeviceAttached ();
    }

}

Finally, whoever needs to listen to the event needs access to the instance of the class holding the event, that is why myOtherCl was made public in this example.

public class ClientApplication
{
    void main()
    {
       ClassLibrary myCL = new ClassLibrary();
       myCL.myOtherCl.DeviceAttached += new EventHandler(myCl_deviceAttached);
    }

    void myCl_deviceAttached(object sender, EventArgs e)
    {
         //do stuff...
    }
}
Lily
As an aside, make sure you copy the event handler before firing it for thread safety: `var ev = DeviceAtached; if (ev != null) ev();`
Tanzelax