c# delegates and event handling
DESCRIPTION
TRANSCRIPT
C# Event Handling
Jussi Pohjolainen Tampere University of Applied Sciences
Method call Directly using System; public class MyClass { public void Method() { Console.WriteLine("Method() begin"); Console.WriteLine("Method() end"); } } public class Test { static void Main(string[] args) { MyClass myObject = new MyClass(); myObject.Method(); } }
About Delegates
• A delegate lets you pass a funcCon as a parameter!
• “Anonymous” invocaCon • You can call a method X() and define the X to be whatever during runCme!
Basic idea behind Delegate: A delegate will allow us to specify what the
func4on we'll be calling looks like without having to specify which func4on to call!
Examples
• public delegate void MyDelegate(); – MyDelegate encapsulates any method with no parameters and no return
• public delegate int ButtonClicked(object o1, object o2);
– BuPonClicked encapsulates any method with return type int and two object parameters
• Just like a declaraCon of a method!
using System; // Declaration of the delegate public delegate void MyDelegate(); class TestDelegate { public static void MyMethod() { Console.WriteLine("Delegate calling!"); } public static void Main() { // Instantiation. MyDelegate encapsulates the method! MyDelegate myDelegate = new MyDelegate(MyMethod); // Invocation.. calls MyMethod! myDelegate(); } }
using System; // Declaration of the delegate public delegate void MyDelegate(); class TestDelegate { public static void MyMethod() { Console.WriteLine("Delegate calling!"); } public static void Main() { // Instantiation. MyDelegate encapsulates the method! MyDelegate myDelegate = new MyDelegate(MyMethod); // Invocation.. calls MyMethod! myDelegate();
// MyDelegate extends class System.Delegate! Console.WriteLine( myDelegate.ToString() ); Console.WriteLine( myDelegate.GetInvocationList().Length ); } }
// Declaration of the delegate public delegate void MyDelegate(); class TestDelegate { public static void A() { Console.WriteLine("A()"); } public static void B() { Console.WriteLine("B()"); } public static void Main() { MyDelegate myDelegate1 = new MyDelegate(A); MyDelegate myDelegate2 = new MyDelegate(B); myDelegate1(); // A() myDelegate2(); // B() } }
// Declaration of the delegate public delegate string MyDelegate(string someParameter); class TestDelegate { public static string A(string s) { Console.WriteLine("A()"); return s; } public static void Main() { MyDelegate myDelegate = new MyDelegate(A); Console.Write( myDelegate("hello") ); // A() hello } }
// Declaration of the delegate public delegate string MyDelegate(string someParameter); class TestDelegate { public static string A(string s) { Console.WriteLine("A()"); return s; } public static void Main() { MyDelegate myDelegate = new MyDelegate(A); someMethod(myDelegate); } public static void someMethod( MyDelegate md ) { Console.Write( md("hello") ); // A() hello } }
Passing object
// MULTICASTING // A multicast delegate maintains a list of functions that will // all be called when the delegate is invoked. // Declaration of the delegate public delegate void MyDelegate(); class TestDelegate { public static void A() { Console.WriteLine("A()"); } public static void B() { Console.WriteLine("B()"); } public static void Main() { MyDelegate myDelegate = new MyDelegate(A); myDelegate += new MyDelegate(B); myDelegate(); // A() B() } }
public delegate void MyDelegate(); class TestDelegate { public static void A() { Console.WriteLine("A()"); } public static void B() { Console.WriteLine("B()"); } public static void Main() { MyDelegate myDelegate = A; myDelegate += B; myDelegate(); // A() B() } }
System.Delegate
• Delegate types are derived from System.Delegate or MulCcastDelegate (subclass of Delegate)
public static void Main()
{
MyDelegate myDelegate = A;
myDelegate += B;
myDelegate(); // A(), B()
int invocationCount = myDelegate.GetInvocationList().GetLength(0);
Console.Write(invocationCount); // 2
}
EVENTS
About Events
• NoCficaCon system • Usually in GUI: buPon clicked -‐> something happens
• Events are declared using delegates
In Java
• In Java: – buPon.addAcConListener( someObjectThatImplementsAcConListener );
• In C# – buPon.ClickedEvent += MyEventHandler;
Listener class Listener { public void MyMethod1() { System.Console.WriteLine("MyMethod1"); } public void MyMethod2() { System.Console.WriteLine("MyMethod2"); } public void MyMethod3() { System.Console.WriteLine("MyMethod3"); } }
public delegate void MyEventHandler(); class GUIWindow { public event MyEventHandler ClickedEvent; // Declare a method that triggers the event: public void ClickHasHappened() { ClickedEvent(); // Calls now MyMethod1, MyMethod2 and MyMethod3 } static void Main() { GUIWindow window = new GUIWindow(); Listener listener = new Listener(); // Subscribe to the event by associating the handlers with the event: window.ClickedEvent += new MyEventHandler(listener.MyMethod1); window.ClickedEvent += new MyEventHandler(listener.MyMethod2); window.ClickedEvent += new MyEventHandler(listener.MyMethod3); // Trigger the event: window.ClickHasHappened(); } }
About event
• What happens here? – public event MyEventHandler ClickedEvent;
• Events are a special kind of mulCcast delegate that can only be invoked from within the class or struct where they are declared (the publisher class
class GUIWindow { // Declare the event of type MyEventHandler. Event handlers // for TriggerIt must have the same signature as MyEventHandler. public event MyEventHandler ClickedEvent; // Declare a method that triggers the event: public void ClickHasHappened() { ClickedEvent(); // Calls now MyMethod1, MyMethod2 and MyMethod3 } static void Main() { GUIWindow window = new GUIWindow(); Listener listener = new Listener(); // Subscribe to the event by associating the handlers with the event: window.ClickedEvent += new MyEventHandler(listener.MyMethod1); window.ClickedEvent += new MyEventHandler(listener.MyMethod2); window.ClickedEvent += new MyEventHandler(listener.MyMethod3); // Trigger the event: window.ClickHasHappened(); window.ClickedEvent(); // Works! Inside GUIWindow class!! } }
class GUIWindow { // Declare the event of type MyEventHandler. Event handlers // for TriggerIt must have the same signature as MyEventHandler. public event MyEventHandler ClickedEvent; // Declare a method that triggers the event: public void ClickHasHappened() { ClickedEvent(); // Calls now MyMethod1, MyMethod2 and MyMethod3 } } class App { static void Main() { GUIWindow window = new GUIWindow(); Listener listener = new Listener(); // Subscribe to the event by associating the handlers with the event: window.ClickedEvent += new MyEventHandler(listener.MyMethod1); window.ClickedEvent += new MyEventHandler(listener.MyMethod2); window.ClickedEvent += new MyEventHandler(listener.MyMethod3); // Trigger the event: window.ClickHasHappened(); window.ClickedEvent(); // DOES NOT WORK! Outside of class GUIWindow! } }
CreaCng the Listener Method
• Usually listener method: – public delegate void MyEventHandler(object sender, EventArgs e);
• Listener receives informaCon: – Who is the publisher? (Sender) – What kind of arguments did the sender pass?
App class App { static void Main() { GUIWindow window = new GUIWindow(); Listener listener = new Listener();
// Subscribe to the event by associating the handlers with the event: window.ClickedEvent += new MyEventHandler(listener.MyMethod1); window.ClickedEvent += new MyEventHandler(listener.MyMethod2); window.ClickedEvent += new MyEventHandler(listener.MyMethod3); // Trigger the event: window.ClickHasHappened(); } }
Listener class Listener
{
public void MyMethod1(object sender, EventArgs e)
{
System.Console.WriteLine("Sender {0}, MyMethod1", sender.ToString());
}
public void MyMethod2(object sender, EventArgs e)
{
System.Console.WriteLine("Sender {0}, MyMethod2", sender.ToString());
}
public void MyMethod3(object sender, EventArgs e)
{
System.Console.WriteLine("Sender {0}, MyMethod3", sender.ToString());
}
}
Publisher public delegate void MyEventHandler(object sender, EventArgs e);
class GUIWindow
{
public event MyEventHandler ClickedEvent;
public void ClickHasHappened()
{
if(ClickedEvent != null)
ClickedEvent(this, null);
}
}
Sender GUIWindow, MyMethod1 Sender GUIWindow, MyMethod2 Sender GUIWindow, MyMethod3
Event Model • The following example followed the guidelines for .NET event model.
• To raise a event, two elements are included – Sender – Data
• .NET Framework has defined following delegate in class library! public delegate void EventHandler( Object sender, EventArgs e
)
App, now Using EventHandler class App { static void Main() { GUIWindow window = new GUIWindow(); Listener listener = new Listener();
// Subscribe to the event by associating the handlers with the event: window.ClickedEvent += new EventHandler(listener.MyMethod1); window.ClickedEvent += new EventHandler(listener.MyMethod2); window.ClickedEvent += new EventHandler(listener.MyMethod3); // Trigger the event: window.ClickHasHappened(); } }
EventHandler is a delegate from class library!
Listener, exactly the same class Listener
{
public void MyMethod1(object sender, EventArgs e)
{
System.Console.WriteLine("Sender {0}, MyMethod1", sender.ToString());
}
public void MyMethod2(object sender, EventArgs e)
{
System.Console.WriteLine("Sender {0}, MyMethod2", sender.ToString());
}
public void MyMethod3(object sender, EventArgs e)
{
System.Console.WriteLine("Sender {0}, MyMethod3", sender.ToString());
}
}
Publisher // We don’t need this!
// public delegate void MyEventHandler(object sender, EventArgs e);
class GUIWindow
{
public event EventHandler ClickedEvent;
public void ClickHasHappened()
{
if(ClickedEvent != null)
ClickedEvent(this, null);
}
}
Sender GUIWindow, MyMethod1 Sender GUIWindow, MyMethod2 Sender GUIWindow, MyMethod3
Passing Data
• The listener receives two things – Sender – Data
• Data is passed as a subclass of EventArgs
Data public class CustomEventArgs : EventArgs { public CustomEventArgs(string s) { msg = s; } private string msg; public string Message { get { return msg; } } }
Pass InformaCon class GUIWindow
{
public event EventHandler ClickedEvent;
public void ClickHasHappened()
{
if(ClickedEvent != null)
ClickedEvent(this, new CustomEventArgs("Click!"));
}
}
Listener class Listener
{
public void MyMethod1(object sender, EventArgs e)
{
System.Console.WriteLine("Event: {0}", e.ToString());
}
…
}
Problem! We can’t call any CustomEvent method, since the parameter is a type of EventArgs. So this does not work: System.Console.WriteLine("Event: {0}", e.Message);
Listener class Listener
{
public void MyMethod1(object sender, CustomEventArgs e)
{
System.Console.WriteLine("Event: {0}", e.Message);
}
…
}
Let’s change the listener. But now the problem is that the used delegate from class library was in the form of public delegate void EventHandler(object sender, EventArgs e);
EventHandler with Generics class GUIWindow
{
public event EventHandler<CustomEventArgs> ClickedEvent;
public void ClickHasHappened()
{
if(ClickedEvent != null)
ClickedEvent(this, new CustomEventArgs("Click!"));
}
}
We can define the second parameter!
EventHandler with Generics class App
{
static void Main()
{
GUIWindow window = new GUIWindow();
Listener listener = new Listener();
// Subscribe to the event by associating the handlers with the event:
window.ClickedEvent += new EventHandler<CustomEventArgs>(listener.MyMethod1);
window.ClickedEvent += new EventHandler<CustomEventArgs>(listener.MyMethod2);
window.ClickedEvent += new EventHandler<CustomEventArgs>(listener.MyMethod3);
// Trigger the event:
window.ClickHasHappened();
}
}
And this is also possible.. class App
{
static void Main()
{
GUIWindow window = new GUIWindow();
Listener listener = new Listener();
// Subscribe to the event by associating the handlers with the event:
window.ClickedEvent += listener.MyMethod1;
window.ClickedEvent += listener.MyMethod2;
window.ClickedEvent += listener.MyMethod3;
// Trigger the event:
window.ClickHasHappened();
}
}