July 5, 2007
Hi Guys
I got the following program from a website. Address is given below. The program uses the built-in EventHandler delegate. I wish to know in what circumstance programmer has to decide whether he has to use custom made EventHandler delegate or built-in EventHandler delegate. Please help.
Thank you
//Use the built-in EventHandler delegate
//http://www.java2s.com/Code/CSharp/Language-Basics/UsethebultinEventHandlerdelegate.htm
using System;
// Declare an event class.
class MyEvent
{
public event EventHandler SomeEvent; // uses EventHandler delegate
// This is called to fire SomeEvent.
public void OnSomeEvent()
{
if(SomeEvent != null)
SomeEvent(this, EventArgs.Empty);
}
}
public class EventDemo6
{
static void handler(object source, EventArgs arg)
{
Console.WriteLine("Event occurred");
Console.WriteLine("Source is " + source);
}
public static void
{
MyEvent evt = new MyEvent();
// Add handler() to the event list.
evt.SomeEvent += new EventHandler(handler);
// Fire the event.
evt.OnSomeEvent();
}
}
Posted Oct 1, 2008, 11:10 AM
AlanPosted Oct 1, 2008, 11:00 AM
It's common for eventhandlers to indicate the source of the event (i.e. which object caused the event to be fired) by having either a source or sender parameter. Information about the event is then usually passed using some kind of EventArgs parameter.
Suppose for example, you were writing a Windows Forms application and you wanted three different TextBoxes to handle the TextChanged event in essentially the same way.
Rather than triplicating the code, you could wire up the TextChanged event for each TextBox to a common eventhandler and the code in this eventhandler would be able to discover which TextBox's Text property had changed by consulting the 'sender' parameter:
private void textBox_TextChanged(object sender, EventArgs e)
{
TextBox tb = (TextBox)sender;
MessageBox.Show(tb.Name + " raised this event");
}
Posted Oct 1, 2008, 10:35 AM
Just for curiosity I altered above your example program.
I removed the “object sender” in the delecate MyEventHandler()method and comment out Console.WriteLine("Source is " + source); (highlighted in yellow) but there is no singificant change in the output.
Please explain the singificant of having “object sender” in the delecate method.
using System;
// Declare a delegate. Delegate event handler named MyEventHandler
delegate void MyEventHandler(MyEventArgs e);
// Declare a custom EventArgs class
class MyEventArgs : EventArgs
{
public int Value;
public MyEventArgs(int value)
{
Value = value;
}
}
// Declare an event class.
class MyEvent
{
public event MyEventHandler SomeEvent; // uses MyEventHandler delegate
public int Value;
// This is called to fire SomeEvent.
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent(new MyEventArgs(Value));
}
}
public class EventDemo6
{
static void handler(MyEventArgs arg)
{
Console.WriteLine("Event occurred");
//Console.WriteLine("Source is " + source);
Console.WriteLine("Value is " + arg.Value);
}
public static void Main()
{
MyEvent evt = new MyEvent();
evt.Value = 42;
// Add handler() to the event list.
evt.SomeEvent += new MyEventHandler(handler);
// Fire the event.
evt.OnSomeEvent();
}
}
/*
Event occurred
Value is 42
*/
AlanPosted Sep 30, 2008, 9:33 AM
Just change this line:
evt.SomeEvent += new EventHandler(handler);
to this, and the results will be the same.
evt.SomeEvent += new EventHandler(X.handler);
Posted Sep 30, 2008, 1:22 AM
Just for curiosity I altered the (thread 6) program.
Suppose we move the handler() method to newly created class X and handler() method still remains static. What are the changes should be done in the Main() method to get the similar output.
// Declare an event class.
class MyEvent
{
public event EventHandler SomeEvent; // uses EventHandler delegate
// This is called to fire SomeEvent.
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent(this, EventArgs.Empty);
}
}
class X
{
public static void handler(object source, EventArgs arg)
{
Console.WriteLine("Event occurred");
Console.WriteLine("Source is " + source);
}
}
public class EventDemo6
{
public static void Main()
{
MyEvent evt = new MyEvent();
// Add handler() to the event list.
evt.SomeEvent += new EventHandler(handler);
// Fire the event.
evt.OnSomeEvent();
}
}
/*
Event occurred
Source is MyEvent
*/
AlanPosted Sep 29, 2008, 2:00 PM
There's no difference between the two. If I remember correctly, the abbreviated form where just the method is specified on the RHS was introduced in C# 2.0:
evt.SomeEvent += handler; // abbreviated form
The compiler translates that to the longer form by inferring the type to be EventHandler because evt.SomeEvent is of that type.
You can still use the longer form if you wish to do so in the interests of clarity.
Posted Sep 29, 2008, 10:46 AM
Thank you very much for explanation, Alan
In my above thread 6th one (code highlighted in brown color). If we use
evt.SomeEvent += handler;
instead of
evt.SomeEvent += new EventHandler(handler);
the program is producing same output. What is the significant of writing following way evt.SomeEvent += new EventHandler(handler); and when we have to write like this. Because many programs are executing without new EventHandler.
AlanPosted Sep 29, 2008, 10:13 AM
That's what's called an 'anonymous method' which is a feature added to C# in version 2.
Basically, these allow you to code one method inside another method, as opposed to creating a separate method and then calling that in the normal way. They're called anonymous because they don't have names.
Instead, the anonymous method is assigned to a compatible named delegate and it is then invoked via this delegate.
To define an anonymous method you use the delegate keyword followed by its parameters (if any) within brackets. The body of the method is then enclosed in {} as a normal method would be but is followed by a semicolon.
So, in the example we have an anonymous method which takes an int parameter and writes some text to the console. As the EventHandler delegate takes an int parameter and doesn't have a return value it is 'compatible' with the anonymous method and so the latter can be assigned to a delegate (MyAnonymousDelegate) of type EventHandler.
This delegate is then added to the invocation list of EventPublisher.MyEvent and so, when this event is fired (by calling DoSomething()) the delegate will automatically be invoked.
The int parameter here is just a 'dummy' parameter which is not actually used in the anonymous method itself. In the event firing code it's given an arbitrary value of 5. Frankly, it's not the best possible example for people who are trying to learn about this concept !
Anonymous methods have some strange properties. In particular, if you use any local variables or 'by value' parameters of the enclosing method within the anonymous method body, then the lifetime of those variables/parameters is extended, and their values are 'captured', until the delegate referencing the anonymous method is destroyed. The variables don't get destroyed (or become eligible for garbage collection) when the enclosing method itself returns.This is called a 'closure' in some other languages.
For more on this topic see this MSDN link:
http://msdn.microsoft.com/en-us/library/0yw3tz5k(VS.80).aspx
Posted Sep 29, 2008, 8:46 AM
In the following program code highlighted in yellow is new to me. Please explain the meaning of it.
using System;
public delegate void EventHandler(int i);
class MainClass
{
static void Main(string[] args)
{
MyEventPublisher EventPublisher = new MyEventPublisher();
EventHandler MyAnonymousDelegate = delegate(int x)
{
Console.WriteLine("Anonymous Event FIRED!");
};
EventPublisher.MyEvent += MyAnonymousDelegate;
EventPublisher.DoSomething();
}
}
public class MyEventPublisher
{
public event EventHandler MyEvent;
public int DoSomething()
{
MyEvent(5);
return 0;
}
}
//Anonymous Event FIRED!
AlanPosted Sep 28, 2008, 9:33 AM
SomeEvent is in fact an event (i.e. a type of delegate) rather than an ordinary method.
When you invoke an event, all the eventhandlers which have been added to the event's invocation list are called in order. This line causes the static method EventDemo6.handler to be added to the invocation list:
evt.SomeEvent += new EventHandler(handler);
Consequently, when SomeEvent is invoked with this line:
SomeEvent(this, EventArgs.Empty);
the 'handler' method gets called automatically and is passed parameters of 'this' (i.e. the current instance of MyEvent) and EventArgs.Empty which is an instance of EventArgs with no event data.
SomeEvent itself does not require any qualification (though you could do this.SomeEvent) as it's being called from within the MyEvent class of which it's an instance event.
Posted Sep 28, 2008, 7:57 AM
To call a method in an instance class Object’s identifier, a dot, and a method call is used to access the instance method in another class.
In the following example (highlighted in yellow) instance method SomeEvent(); in the MyEvent class is accessing handler() in the EventDemo6 class but Object’s identifier, a dot, and a method call is not used to access it.
Because handler() method is a static method. Is that the reason for that?
using System;
// Declare an event class.
class MyEvent
{
public event EventHandler SomeEvent; // uses EventHandler delegate
// This is called to fire SomeEvent.
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent(this, EventArgs.Empty);
}
}
public class EventDemo6
{
static void handler(object source, EventArgs arg)
{
Console.WriteLine("Event occurred");
Console.WriteLine("Source is " + source);
}
public static void Main()
{
MyEvent evt = new MyEvent();
// Add handler() to the event list.
evt.SomeEvent += new EventHandler(handler);
// Fire the event.
evt.OnSomeEvent();
}
}
/*
Event occurred
Source is MyEvent
*/
AlanPosted Sep 22, 2008, 6:08 AM
Posted Sep 21, 2008, 4:55 PM
In the above program following output is indicating values after change. But what were the values before change. Please explain.
/*
The student has changed.
ID# 2345 GPA 0
The student has changed.
ID# 4567 GPA 0
The student has changed.
ID# 4567 GPA 3.2
*/
AlanPosted Sep 21, 2008, 7:40 AM
The purpose of this line:
stu = student;
was to set the private field 'stu' to refer to the Student object which is being passed to the EventListener constructor.
When that line is removed, 'stu' will be null which is the default value for all reference types and any attempt to use some instance member of the Student class, such as the changed event, via the 'stu' field will therefore result in a null reference exception.
Posted Sep 21, 2008, 6:35 AM
What is meant by the following line. I couldn’t understand it. Please explain in detail.
The field 'stu' (now renamed 'student') is no longer being set to a Student object and so has its default value of 'null'.
AlanPosted Sep 21, 2008, 5:38 AM
The problem is caused by the commenting out of this line:
//stu = student;
The field 'stu' (now renamed 'student') is no longer being set to a Student object and so has its default value of 'null'.
You therefore get a null reference exception as soon as the runtime hits this line:
student.Changed += new ChangedEventHandler(StudentChanged);
However, if you change the commented out line to this:
this.student = student;
then it will work fine as it did before.
Posted Sep 20, 2008, 8:23 PM
class EventListener
{
private Student student;
public EventListener(Student student)
{
//stu = student;
student.Changed += new ChangedEventHandler(StudentChanged);
}
public void StudentChanged(object sender, EventArgs e)
{
Console.WriteLine("The student has changed.");
Console.WriteLine(" ID# {0} GPA {1}", student.GetId(), student.GetGpa());
}
}
Just for curiosity I replaced the stu by student (Changes highlighted in yellow in above) in the following program but after the changes program is not executing. Please explain the reason.
using System;
public delegate void ChangedEventHandler(object sender, EventArgs e); // declare a delegate
public class Student
{
private int idNum;
private double gpa;
public event ChangedEventHandler Changed;
//delcares a event for the delegate
public int GetId()
{
return idNum;
}
public double GetGpa()
{
return gpa;
}
public void SetId(int num)
{
idNum = num;
OnChanged(EventArgs.Empty);
}
public void SetGpa(double avg)
{
gpa = avg;
OnChanged(EventArgs.Empty);
}
public void OnChanged(EventArgs e)
{
Changed(this, e);
}
}
class EventListener
{
private Student stu;
public EventListener(Student student)
{
stu = student;
stu.Changed += new ChangedEventHandler(StudentChanged);
}
public void StudentChanged(object sender, EventArgs e)
{
Console.WriteLine("The student has changed.");
Console.WriteLine(" ID# {0} GPA {1}", stu.GetId(), stu.GetGpa());
}
}
class DemoStudentEvent
{
public static void Main()
{
Student oneStu = new Student();
EventListener listener = new EventListener(oneStu);
oneStu.SetId(2345);
oneStu.SetId(4567);
oneStu.SetGpa(3.2);
}
}
/*
The student has changed.
ID# 2345 GPA 0
The student has changed.
ID# 4567 GPA 0
The student has changed.
ID# 4567 GPA 3.2
*/
AlanPosted Sep 18, 2008, 3:33 PM
Sure, try this variation of the program in your first post on this thread:
using System;
// Declare a custom EventArgs class
class MyEventArgs : EventArgs
{
public int Value;
public MyEventArgs(int value)
{
Value = value;
}
}
// Declare a delegate
delegate void MyEventHandler(object sender, MyEventArgs e);
// Declare an event class.
class MyEvent
{
public event MyEventHandler SomeEvent; // uses MyEventHandler delegate
// This is called to fire SomeEvent.
public int Value;
public void OnSomeEvent()
{
if(SomeEvent != null)
SomeEvent(this, new MyEventArgs(Value));
}
}
public class EventDemo6
{
static void handler(object source, MyEventArgs arg)
{
Console.WriteLine("Event occurred");
Console.WriteLine("Source is " + source);
Console.WriteLine("Value is " + arg.Value);
}
public static void Main()
{
MyEvent evt = new MyEvent();
evt.Value = 42;
// Add handler() to the event list.
evt.SomeEvent += new MyEventHandler(handler);
// Fire the event.
evt.OnSomeEvent();
}
}
Posted Sep 18, 2008, 2:14 PM
It is much appreciated if you support with a program which has a custom EventArgs and does return data.
AlanPosted Jul 5, 2007, 2:18 PM
The standard EventHandler delegate should only be used if your Event doesn't return any data in the second EventArgs parameter, which is the case in your sample code.
If your event does return data, then you should create a custom 'EventArgs' type which exposes that data and then create a new eventhandler type whose second parameter is of your custom data type.
See this link for further information:
http://msdn2.microsoft.com/en-us/library/system.eventhandler.aspx