Is there a better way to initialize EventHandlers in C# - c#

Let's say that I am writing a class library of some sort. I have a class:
public class PopupControl : UserControl {
// Some code
public event EventHandler PopupFinished;
}
If I want to handle this event in another class, I just use the += operator and nothing special happens. However, when the event is not handled anywhere, PopupFinished is null. And when I call PopupFinished (this, EventArgs.Empty), I get a NullReferenceException. So I need to do this:
public PopupControl () {
PopupFinished += popupFinished;
//Some more code
}
private void popupFinished (object sender, EventArgs e) {}
This doesn't sound like a good programming practice though. (or is it?)
Then I thought of another way:
try {
PopupFinished (this, EventArgs.Empty);
} catch (NullReferenceException) {}
But that doesn't sound right either.
Please tell me which of the above is better and whether there is another way to do that. Thanks!

Do a test to check PopupFinished is not null before calling it.
if(PopupFinished != null)
PopupFinished();

Related

Adding Event to a Method

I have a HTTP class that I've created, and I would to, if possible, attach a method each time either HTTP.post() or HTTP.get() is called. I'd like to be able to attach the event either before, or after.
I see this being done in a lot of Frameworks for the web, such as Wordpress and Symfony, but I'd like to do something similar on my WinForms app.
What design pattern am I looking for to achieve this so I can go and Google it.
You can create events on your objects and invoke them from anywhere in your code. I do this quite often.
public event EventHandler Getting;
public event EventHandler Setting;
void get()
{
if (Getting != null)
Getting.Invoke(this, EventArgs.Empty);
}
void post()
{
if (Setting != null)
Setting.Invoke(this, EventArgs.Empty);
}
Then other classes can handle these events something like this:
myHttp.Getting += myHttp_Getting;
public void myHttp_Getting(object sender, EventArgs e)
{
}
Edits:
You could also invoke the event like this:
void post()
{
if (Setting != null)
Setting(this, EventArgs.Empty);
}
You can only invoke an event from within its own class. This is not a problem because being able to do otherwise would cause really confusing code. Always check if it is null, because if there are no subscribers it will be null and will through a NullReferenceException when you invoke it.

Delegate event issue

I am new in c# development. I just trying to study the delegate feature. Based on the articles and notes I read about delegates, I tried to write a sample code to implement delegate based on what I understood from those notes and articles.
But I am getting an error while running the sample
"Object reference not set to an instance of an object."
What is the problem here ?. or Did I implemented the delegate in correct way ? or Is my concept about delegate is wrong ?..
Please help. Thanks in advance.
I posted my code below.
default.aspx.cs
public partial class _Default : System.Web.UI.Page
{
TestClass myObject = new TestClass();
protected void Page_Load(object sender, EventArgs e)
{
myObject.MyDelegateEvent += new TestClass.MyDelegate(myObject_MyDelegateEvent);
}
void myObject_MyDelegateEvent(object sender, EventArgs e)
{
Console.WriteLine("Delegate event called");
}
}
TestClass
public class TestClass
{
public delegate void MyDelegate(object sender, EventArgs e);
public event MyDelegate MyDelegateEvent;
public TestClass()
{
MyDelegateEvent(this, null); // Here getting error "Object reference not set to an instance of an object."
}
}
What you are trying is: raising the event in the constructor itself, i.e. at the time when there is no subscriber for your event hence MyDelegateEvent is null.
Best option is to null check before raising the event
//Check for not null
if(MyDelegateEvent != null)
{
MyDelegateEvent(this, null);
}
Always test for null before raising the event:
if (this.MyDelegateEvent != null)
{
// Raises the event here
}
If no handler is attached to your event when it is raised (which is the case here as it's raised in the constructor), a null reference exception can be thrown.
EDIT:
For the sake of completeness, when no event argument is used, you should use EventArgs.Empty instead of null:
if (this.MyDelegateEvent != null)
{
this.MyDelegateEvent(this, EventArgs.Empty);
}
Also, there is a EventHandler delegate that can be used when you do not specify any event argument. This is useful as you don't have to write your own each time.
When you declare an event, the event is initialised to null. So, in your TestClass constructor you attempt to fire the event but as the event is null this causes the NullReferenceException you are seeing.
To avoid this you need to register an event handler or check for null before raising the event:
if (MyDelegateEvent != null)
{
MyDelegateEvent(...)
}
Another trick is to initialise the event to an empty delegate when you create it which means you can skip the null checks.
public event MyDelegate MyDelegateEvent = delegate {}; // registers a delegate that does nothing
Minor point about some of the code above. It is possible for MyDelegateEvent to be changed between being checked and used. The recommended form (Framework Design Guidelines) is along the lines of
var del = MyDelegateEvent;
if (del != null) {
del(...);
}
hth,
Alan.

How to add an event to a UserControl in C#?

I have a UserControl which contains 3 labels. I want to add an event for it, which occurs when the text of one of the labels changed.
I am using Visual Studio 2010
First, you need to declare the event within your class (alongside your methods and constructors):
public event EventHandler LabelsTextChanged;
Then you need to create a method to handle the individual labels' TextChanged events.
private void HandleLabelTextChanged(object sender, EventArgs e)
{
// we'll explain this in a minute
this.OnLabelsTextChanged(EventArgs.Empty);
}
Somewhere, probably in your control's constructor, you need to subscribe to the label's TextChanged events.
myLabel1.TextChanged += this.HandleLabelTextChanged;
myLabel2.TextChanged += this.HandleLabelTextChanged;
myLabel3.TextChanged += this.HandleLabelTextChanged;
Now for the HandleLabelsTextChanged method. We could raise LabelsTextChanged directly; however, the .NET framework design guidelines say that is it a best practice to create an OnEventName protected virtual method to raise the event for us. That way, inheriting classes can "handle" the event by overriding the OnEventName method, which turns out to have a little better performance than subscribing to the event. Even if you think you will never override the OnEventName method, it is a good idea to get in the habit of doing it anyway, as it simplifies the event raising process.
Here's our OnLabelsTextChanged:
protected virtual void OnLabelsTextChanged(EventArgs e)
{
EventHandler handler = this.LabelsTextChanged;
if (handler != null)
{
handler(this, e);
}
}
We have to check for null because an event without subscribers is null. If we attempted to raise a null event, we would get a NullReferenceException. Note that we copy the event's EventHandler to a local variable before checking it for null and raising the event. If we had instead done it like this:
if (this.LabelsTextChanged != null)
{
this.LabelsTextChanged(this, e);
}
We would have a race condition between the nullity check and the event raising. If it just so happened that the subscribers to the event unsubscribed themselves just before we raised the event but after we checked for null, an exception would be thrown. You won't normally encounter this issue, but it is best to get in the habit of writing it the safe way.
Edit: Here is how the public event EventHandler LabelsTextChanged; line should be placed:
namespace YourNamespace
{
class MyUserControl : UserControl
{
// it needs to be here:
public event EventHandler LabelsTextChanged;
...
}
}
Here are the framework design guidelines on event design for further reading.
First you should declare an event in your usercontrol for example:
public event EventHandler TextOfLabelChanged;
then you have to call the call back function that is bound to your event(if there's any) in runtime.You can do this by handling the TextChanged event of a label like this:
public void LabelTextChanged(object sender,EventArgs e)
{
if(TextOfLabelChanged!=null)
TextOfLabelChanged(sender,e);
}
You can have your own EventArgs object if you like.
somewhere in your code you should bound your label TextChanged event to this method like this:
_myLabel.TextChanged+=LabelTextChanged;
public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;
// ...
protected void MyTextBox_TextChanged(object sender, EventArgs e)
{
if (LabelTextChanged != null) {
LabelTextChanged(this, e);
}
}
compile error, which says: "Expected class, delegate, enum, interface, or struct" on the second line it seems to have a problem with "event...
These 2 lines need to be INSIDE the class declaration.
public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;
There is a very simple way to do that!
On the UserControl Form :
change properties to public to access everywhere
on the main form , where you are using UserControl:
.5: in the using region add using userControl1=UserControl.userControl1
1.Add 'Laod' event to your UserControl :
this.userControl1.Load += new System.EventHandler(this.userControl1_Load);
2.In the userControl1_Load :
private void userControl1_Load(object sender, EventArgs e)
{
(sender as UserControl1).label1.TextChanged += label1_TextChanged;
//add a 'TextChanged' event to the label1 of UserControl1
OR use direct cast:
((UserControl1) sender).label1.TextChanged += label1_TextChanged;
}
3.In th label1_TextChanged:
private void label1_TextChanged(object sender, EventArgs e)
{
//do whatever you want
}
You must be declaring the event and delegate within the Namespace. Try to bring the code within the class Scope. It will run fine.

Why must someone be subscribed for an event to occur?

Some text before the code so that the question summary isn't mangled.
class Tree
{
public event EventHandler MadeSound;
public void Fall() { MadeSound(this, new EventArgs()); }
static void Main(string[] args)
{
Tree oaky = new Tree();
oaky.Fall();
}
}
I haven't used events much in C#, but the fact that this would cause a NullRefEx seems weird. The EventHandler reference is considered null because it currently has no subsribers - but that doesn't mean that the event hasn't occurred, does it?
EventHandlers are differentiated from standard delegates by the event keyword. Why didn't the language designers set them up to fire silently in to the void when they have no subscribers? (I gather you can do this manually by explicitly adding an empty delegate).
Well, the canonical form is:
void OnMadeSound()
{
if (MadeSound != null)
{
MadeSound(this, new EventArgs());
}
}
public void Fall() { OnMadeSound(); }
which is very slightly faster that calling an empty delegate, so speed won out over programming convenience.
Another good way I've seen to get around this, without having to remember to check for null:
class Tree
{
public event EventHandler MadeSound = delegate {};
public void Fall() { MadeSound(this, new EventArgs()); }
static void Main(string[] args)
{
Tree oaky = new Tree();
oaky.Fall();
}
}
Note the anonymous delegate - probably a slight performance hit, so you have to figure out which method (check for null, or empty delegate) works best in your situation.
The recommended pattern is (.net 2.0+)
public class MyClass
{
public event EventHandler<EventArgs> MyEvent; // the event
// protected to allow subclasses to override what happens when event raised.
protected virtual void OnMyEvent(object sender, EventArgs e)
{
// prevent race condition by copying reference locally
EventHandler<EventArgs> localHandler = MyEvent;
if (localHandler != null)
{
localHandler(sender, e);
}
}
public void SomethingThatGeneratesEvent()
{
OnMyEvent(this, EventArgs.Empty);
}
}
I see a lot of recommendations for an empty delegate{} in an initializer, but I totally disagree with it. If you follow the above pattern you only check the event != null in one place. The empty delegate{} initializer is a waste because it's an extra call per event, it wastes memory, and it still can fail if MyEvent was set to null elsewhere in my class.
* If your class is sealed, you wouldn't make OnMyEvent() virtual.
You need to understand what your event declaration is actually doing. It's declaring both an event and a variable, When you refer to it within the class, you're just referring to the variable, which will be null when there are no subscribers.
Very Zen, eh?
You have to test for null when you want to raise an event:
protected void OnMyEvent()
{
if (this.MyEvent != null) this.MyEvent(this, EventArgs.Empty);
}
It would be nice if you didn't have to bother with this, but them's the breaks.
James provided a good technical reasoning, I would also like to add that I have seen people use this an advantage, if no subscribers are listening to an event, they will take action to log it in the code or something similar. A simpl example, but fitting in this context.
What is the point of raising an event if no one is listening? Technically, its just how C# chose to implement it.
In C#, an event is a delegate with some special feathers. A delegate in this case can be viewed as a linked list of function pointers (to handler methods of subscribers). When you 'fire the event' each function pointer is invoked in turn. Initially the delegate is a null object like anything else. When you do a += for the first subscribe action, Delegate.Combine is called which instantiates the list. (Calling null.Invoke() throws the null exception - when the event is fired.)
If you still feel that "it must not be", use a helper class EventsHelper as mentioned here with old and improved 'defensive event publishing' http://weblogs.asp.net/rosherove/articles/DefensiveEventPublishing.aspx
Using an extension method would be helpful in this scenario.
public static class EventExtension
{
public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs
{
if (handler != null)
{
handler(obj, args);
}
}
}
It can then be used like below.
public event EventHandler<YourEventArgs> YourEvent;
...
YourEvent.RaiseEvent(this, new YourEventArgs());
Thank you for the responses. I do understand why the NullReferenceException happens and how to get around it.
Gishu said
What is the point of raising an event if no one is listening?
Well, maybe it's a terminology thing. The appeal of an "event" system seems to me that all the responsibility of the fallout of the event that took place should be on the watchers and not the performer.
Perhaps a better thing to ask is: If a delegate field is declared with the event keyword in front of it, why doesn't the compiler translate all instances of:
MadeSound(this, EventArgs.Empty)
to
if (MadeSound != null) { MadeSound(this, EventArgs.Empty); }
behind the scenes in the same manner that other syntax shortcuts are? The number of boilerplate OnSomeEvent null checking methods that people have to write manually must be colossal.

Calling C# events from outside the owning class?

Is it possible under any set of circumstances to be able to accomplish this?
My current circumstances are this:
public class CustomForm : Form
{
public class CustomGUIElement
{
...
public event MouseEventHandler Click;
// etc, and so forth.
...
}
private List<CustomGUIElement> _elements;
...
public void CustomForm_Click(object sender, MouseEventArgs e)
{
// we might want to call one of the _elements[n].Click in here
// but we can't because we aren't in the same class.
}
}
My first thought was to have a function similar to:
internal enum GUIElementHandlers { Click, ... }
internal void CustomGUIElement::CallHandler(GUIElementHandler h, object[] args) {
switch (h) {
case Click:
this.Click(this, (EventArgs)args[0]);
break;
... // etc and so forth
}
}
It's a horribly ugly kludge, but it should work... There must be a more elegant solution though? The .NET library does this all the time with message handlers and calling events in Control's. Does anyone else have any other/better ideas?
You just need to add a public method for invoking the event. Microsoft already does this for some events such as PerformClick for controls that expose a Click event.
public class CustomGUIElement
{
public void PerformClick()
{
OnClick(EventArgs.Empty);
}
protected virtual void OnClick(EventArgs e)
{
if (Click != null)
Click(this, e);
}
}
You would then do the following inside your example event handler...
public void CustomForm_Click(object sender, MouseEventArgs e)
{
_elements[0].PerformClick();
}
The event keyword in c# modifies the declaration of the delegate. It prevents direct assignment to the delegate (you can only use += and -= on an event), and it prevents invocation of the delegate from outside the class.
So you could alter your code to look like this:
public class CustomGUIElement
{
...
public MouseEventHandler Click;
// etc, and so forth.
...
}
Then you can invoke the event from outside the class like this.
myCustomGUIElement.Click(sender,args);
The drawback is that code using the class can overwrite any registered handlers very easily with code like this:
myCustomGUIElement.Click = null;
which is not allowed if the Click delegate is declared as an event.
You can shorten the code suggested in the accepted answer a lot using the modern syntax feature of the .NET framework:
public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);
You really should wrap the code you want to be able to execute from the outside in a method. That method can then do whatever your event would do - and that event would also instead call that method.

Categories

Resources