Bahaïka
Bahaïka

Reputation: 725

Raising an event inside a class and use an handler on another class

I'm making a Class Library and I'm using it inside a Windows Form Program. I would like to handle an event of this library inside the program. I'm using this code :

Class inside the library :

public class KSEDataServIO
{
    public delegate void IsReadyForUseEventHandler(object sender, IsReadyForUseEventArgs e);
    public event IsReadyForUseEventHandler IsReadyForUse;
    public KSEDataServIO(){
       EvArg = new IsReadyForUseEventArgs("AuthOkay");
       IsReadyForUse(this, EvArg); //This is where i get the issue.
    }
}

And, In the Window Form I'm doing this :

private void button1_Click(object sender, EventArgs e) {
            KSEDataServIO con = new KSEDataServIO();
            con.IsReadyForUse += new KSEDataServIO.IsReadyForUseEventHandler(con_IsReadyForUse);
}

void con_IsReadyForUse(object sender, IsReadyForUseEventArgs e)
{
     MessageBox.Show(e.Etat);
}

I got a NullReferenceException to the line 'IsReadyForUse(this, EvArg);' inside the class library. Any idea ?

Upvotes: 1

Views: 1761

Answers (2)

ChrisWue
ChrisWue

Reputation: 19020

Your problem is that you raise the event inside the constructor of KSEDataServIO. At that point nothing has subscribed to that event handler and therefore it raises a null reference exception.

So one thing is to properly raise the event handler for which this pattern is commonly used:

public delegate void IsReadyForUseEventHandler(object sender, IsReadyForUseEventArgs e);
public event IsReadyForUseEventHandler IsReadyForUse;

void OnIsReadyForUse(IsReadyForUseEventArgs e)
{
    var handler = IsReadyForUse;
    if (handler != null)
    {
        handler(this, e);
    }
}

Then use it like this to raise the event:

OnIsReadyForUse(new IsReadyForUseEventArgs("AuthOkay"))

Secondly raising the event inside your constructor doesn't make much sense as nothing could possibly have yet subscribed to the handler (unless you pass a handler as constructor parameter). You will need to find another trigger where you can raise the event later on.

Also you should expose a IsReady property in your class. So if a user comes along later it can query the object if it is already ready. If the IsReady event was already raised when you start using the object somewhere then you might miss the event otherwise.

Edit: You could pass a handler to the constructor if you really wanted to do this:

public KSEDataServIO(IsReadyForUseEventHandler handler)
{
   IsReadyForUse += handler;
   OnIsReadyForUse(new IsReadyForUseEventArgs("AuthOkay")); // see pattern above
}

However as your event provides this as the sender you pass a reference to an object before it has finished executing the whole constructor potentially leading to problems which are hard to track down. If the only place where you are ever going to raise the event is the end of the constructor then you don't really need it.

Upvotes: 2

Darren Lewis
Darren Lewis

Reputation: 8488

You're raising the event in the constructor before you've assigned con_IsReadyForUse.

Upvotes: 0

Related Questions