I defined an event on my class and I want to make one of the methods of the class a handler for the event.
This is what I have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegatesAndEvents
{
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.NameChangeEventHandler += new Person.NameChangeEventHandlerDel;
p.Name = "Paul";
}
}
class Person
{
#region Events
public delegate void NameChangeEventHandlerDel(object sender, EventArgs args);
public event EventHandler NameChangeEventHandler;
protected void NameChange(EventArgs arg)
{
Console.WriteLine("Name change...");
}
#endregion
#region Properties
private string name;
public string Name
{
get { return name; }
set
{
NameChange(null);
name = value;
}
}
#endregion
public Person(string name = "John")
{
this.name = name;
}
}
}
How can I register the event handler without having to do it in Main?
I changed and commented your code, but I'm not really sure about what you intend to do:
Call a method in your person and start raising the events in that method. When ever a event is raised by the Person class, since the main has subscribed to this event. You get a call back shoot into Main.
You have just subscribed the event. Where is the event body??
If you rem the winforms events. You subscribe to lets say button click event like btn_Click(object, eventArgs).. Then you give a body for this event method right? Same way here.
Have a read through How to: Publish Events that Conform to .NET Framework Guidelines for more information on how to create and use events. The example there isn't quite as clear as it should be so I'll walk through the process here.
The first part needed to define an event is the event handler delegate to be used. It's the method signature that is required for all who wishes to receive notifications on this event. You generally don't have to create a new delegate yourself, you should use the existing
EventHandler
(or genericEventHandler<TEventArgs>
) delegate. You'd use the non-generic version if you don't need to include any other arguments about the event. Otherwise you'd use the generic version. In your case, there aren't any other arguments needed about the event so you should use the non-genericEventHandler
.(If you wanted to be able to include information like the old value and new value as arguments, you'd use the generic version with an appropriate class derived from
EventArgs
. A bit of an advanced topic so we'll skip that.)The next part is to define the event. It's just as simple as if you were defining a property for your class. The difference here is that you'd use the
event
keyword to specify that you are defining an event followed by the delegate to use and the name of the event. The convention for naming the event for changing properties is usually in the pattern,PropertyNameChanged
. Since you want an event that is fired when theName
property changes, you should name it:NameChanged
.An optional (but highly recommended) step is to define a method used to raise the event. This will make it easier for you to raise the event when you want. Usual naming convention is similar to how the event is named. This time,
OnEventName
. So you'd name itOnNameChanged
here. It is usually defined as a protected virtual method that way derived classes could easily override this. The arguments to the function should be the arguments that is needed for the event. Since there are no arguments here, it could be left without arguments in the signature.With that all in place, it's just a matter of calling the event handlers. It's just a delegate so just call on it. But don't forget to check if it's
null
first, that would signify that no event handlers were registered. The arguments to the handler should bethis
(the object that is raising the event) and whatever the arguments should be. In this case, there aren't arguments but you should return an instance of the "empty"EventArgs
.The final part is to wire this up in your properties. You'd want to raise the event if an assignment would change the value of the property. Pretty simple, just check to see if the old value is different from the new value. If it is, change it and raise the event. Otherwise, do nothing else.
Now that we're all set with the event, you want to be able to register some handlers for this event. To be able to do this, first we'd need the instance of the
Person
that we want to wait forName
changes and we need a event handling method with the right signature for the event. The event is defined to use theEventHandler
delegate so we need a method with the signature:void NameChanged(object sender, EventArgs e)
. Remember, thesender
argument is the object that raised the event. In this case, it is aPerson
object so we can get the object that changed and get inspect the properties if we wanted to. You can name this whatever you want. The pattern I go for personally is:InstanceName_EventName
. So in this case, I'd name it:person_NameChanged
.Once that is defined, add the handler to the event and we'll be notified if anything changes.
If you wanted the handler to be completely within the class, you could register the event within the class. No need to wire it up externally. You could do it from the constructor. I would not suggest adding your code to the
OnNameChanged()
event raising method, that method should be reserved for simply raising the event.Note that in this particular example, the handler is static so it isn't tied to a single instance. It would work for any
Person
in general. Just be aware that since it is static, you would not be able to usethis
within the method which is why the cast on sender is necessary. Whether it is static or not is up to you ultimately, either way should be fine.So to put this all together, this is what you could do:
I don't really get what your intentions are, but:
you have not subscribed a function in Program class that will handle the name change event.
you have not fired the event in Person class. you should write:
protected void NameChange(EventArgs arg) { Console.WriteLine("Name change..."); NameChangeEventHandler(); }