When I was reading on delegates. I decided to write a simple example as Console application which could mimic button actions.
So I create a delegate and try to subscribe two methods(OnSomethingHappened_1 and OnSomethingHappened_2) to the myButtonObj.Click event. Below shows what I did so far:
using System;
namespace DelegateConsoleExample
{
public delegate void MyEventHandler(string foo);
class Program
{
public void Main(string[] args)
{
MyButton myButtonObj = new MyButton();
myButtonObj.Click += new MyEventHandler(OnSomethingHappened_1);
myButtonObj.Click += new MyEventHandler(OnSomethingHappened_2);
}
public static void OnSomethingHappened_1(string bar)
{
Console.WriteLine("x method runs");
Console.ReadKey();
}
public static void OnSomethingHappened_2(string bar)
{
Console.WriteLine("y method runs");
Console.ReadKey();
}
}
public class MyButton
{
MyEventHandler myField;
public event MyEventHandler Click
{
add { myField += value; }
remove { myField -= value; }
}
}
}
But I couldnt figure out where I am doing wrong since I cannot invoke the event by myButtonObj.Click("foo");
Firstly when you define a delegate as an event you can only invoke it from inside the class itself.
Secondly when you explicitly define add/remove for the event you have to use the backing field to invoke it.
So you may do this to call it:
public class MyButton
{
MyEventHandler myField;
public event MyEventHandler Click
{
add { myField += value; }
remove { myField -= value; }
}
public void Invoke(string s)
{
myField(s);
}
}
//and then calling it like this:
myButtonObj.Invoke("foo");
Related
I am trying to use my own events in several classes.
I've seen similar questions. But i need a clear, correct example, like in ABC-book.
class Class2
{
public bool Do_Some_thing()
{
bool there_is_no_errors=false;
if (there_is_no_errors)
trigger_User_event();
return true;
}
}
How this should be realized? Creating a new class or just in main code i can create obj-event and give it my class2?
public delegate void TriggerMyEvent(string message);
public event TriggerMyEvent MyEvent;
Events are declared and generated in a class and are associated with the event handler by using a delegate in the same class or in another class.
The class containing the event is used to publish the event. This is called the publisher class. Other classes that accept this event are called subscriber classes.
To declare an event inside a class, you must first declare the its delegate type. Then, declare the event using keyword event.
Here is a simple demo about how to subscribe to an event.
class Program
{
static void Main(string[] args)
{
EventTest e = new EventTest(); /* Instantiate the object, without triggering event */
subscribEvent v = new subscribEvent(); /* Instantiate object */
e.ChangeNum += new EventTest.NumManipulationHandler(v.printf); /* subscribe the event */
e.SetValue(7);
e.SetValue(11);
}
}
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum(); /* Trigger the event */
}
else
{
Console.WriteLine("event not fire");
Console.ReadKey(); /* Press enter to continue */
}
}
public EventTest()
{
int n = 5;
SetValue(n);
}
public void SetValue(int n)
{
if (value != n)
{
value = n;
OnNumChanged();
}
}
}
// Subscriber class
public class subscribEvent
{
public void printf()
{
Console.WriteLine("event fire");
Console.ReadKey(); /* Press enter to continue */
}
}
I have a first class that raises an event when some changes occur:
public class MyFirstClass {
public event EventHandler ChangesHappened;
public MyFirstClass() {
}
public void MyMethod() {
//Thing happened
ChangesHappened?.Invoke(this, new EventArgs());
}
}
I also have a second class that have a list of FirstClass:
public class MySecondClass {
private List<MyFirstClass> first;
public MySecondClass() {
foreach(var f in first) {
first.Changed += (s, e) => {};
}
}
}
And last I have a WPF application with an instance of SecondClass. How can I handle the Changed event (FirstClass) from WPF? Should I create an event in SecondClass and raise it inside first.Changed += (s, e) => { NewEvent(this, new EventArgs()); } and then catch this in the WPF?
The objective is get the Changed event in the WPF application.
It seems to me that this is the simplest answer:
public class MySecondClass
{
public event EventHandler ChangesHappened;
private List<MyFirstClass> first;
public MySecondClass()
{
foreach (var f in first)
{
f.ChangesHappened += (s, e) => ChangesHappened?.Invoke(s, e);
}
}
}
Another option is to use Microsoft's Reactive Framework which lets you pass events (well observables) around as first-class language citizens.
You could do this:
void Main()
{
var msc = new MySecondClass();
msc.Changes.Subscribe(ep =>
{
/* Do stuff with
ep.Sender
ep.EventArgs
from the `MyFirstClass` instances
*/
});
}
public class MyFirstClass
{
public event EventHandler ChangesHappened;
public IObservable<EventPattern<EventArgs>> Changes;
public MyFirstClass()
{
this.Changes = Observable.FromEventPattern<EventHandler, EventArgs>(
h => this.ChangesHappened += h, h => this.ChangesHappened += h);
}
public void MyMethod()
{
ChangesHappened?.Invoke(this, new EventArgs());
}
}
public class MySecondClass
{
public IObservable<EventPattern<EventArgs>> Changes;
private List<MyFirstClass> first = new List<MyFirstClass>();
public MySecondClass()
{
this.Changes = first.Select(f => f.Changes).Merge();
}
}
As #Enigmativity already mentioned: When you have a class, that has to manage other classes (bunch of MyFirstClass references) then you have to forward your events from sub class to manager class.
public class MySecondClass
{
public event EventHandler Changed;
private List<MyFirstClass> firstClassList;
public MySecondClass()
{
firstClassList = new List<MyFirstClass>();
}
public void AddMyFirstClassList(List<MyFirstClass> firstClassList)
{
foreach (var firstClass in firstClassList)
AddMyFirstClass(firstClass);
}
public void AddMyFirstClass(MyFirstClass firstClass)
{
// from sub class to manager class
firstClass.Changed += firstClass_Changed;
firstClassList.Add(firstClass);
}
private void firstClass_Changed(object sender, EventArgs args)
{
Changed?.Invoke(sender, args);
}
public void RemoveMyFirstClass(MyFirstClass firstClass)
{
MyFirstClass.Remove -= firstClass_Changed;
firstClassList.Remove(firstClass);
}
}
Another option is to pass a callback function. You should avoid this, unless you need it explicity:
public class MyFirstClass
{
EventHandler handler;
public MyFirstClass(EventHandler handler)
{
this.handler = handler;
}
public void MyMethod()
{
handler?.Invoke(this, new EventArgs());
}
}
public class MySecondClass
{
private List<MyFirstClass> firstClassList;
public MySecondClass()
{
firstClassList = new List<MyFirstClass>();
}
// you have instantiated your class and passed your callback function previously.
public void AddMyFirstClass(MyFirstClass firstClass)
{
firstClassList.Add(firstClass);
}
// for demonstrating the instantiation.
public void AddMyFirstClass(EventHandler handler)
{
firstClassList.Add(new MyFirstClass(handler));
}
}
Given the following code:
public delegate void Signal();
public static class SignalExtensions
{
public static void SafeInvoke(this Signal signal)
{
Signal copy = signal;
if (copy != null)
{
copy();
}
}
}
public class RootEventSource
{
public event Signal RootEvent;
public void Raise()
{
this.RootEvent.SafeInvoke();
}
}
public class EventForwarder
{
private readonly RootEventSource rootEventSource;
public EventForwarder(RootEventSource rootEventSource)
{
this.rootEventSource = rootEventSource;
// this is the critical part
this.rootEventSource.RootEvent
+= () => this.AnotherEvent.SafeInvoke();
}
public event Signal AnotherEvent;
// just an example of another method which is using the root event source
public override string ToString()
{
return this.rootEventSource.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var rootEventSource = new RootEventSource();
var eventForwarder = new EventForwarder(rootEventSource);
eventForwarder.AnotherEvent += HandleAnotherEvent;
rootEventSource.Raise();
Console.WriteLine("done");
Console.ReadKey();
}
private static void HandleAnotherEvent()
{
Console.WriteLine("received AnotherEvent");
}
}
This results in the output:
received AnotherEvent
done
Now I make a slight change to the implementation of EventForwarder to use a method group for forwarding the event:
public EventForwarder(RootEventSource rootEventSource)
{
this.rootEventSource = rootEventSource;
this.rootEventSource.RootEvent += this.AnotherEvent.SafeInvoke;
}
The output becomes:
done
So AnotherEvent is not raised.
Until now i would have considered the two lines:
this.rootEventSource.RootEvent += this.AnotherEvent.SafeInvoke;
this.rootEventSource.RootEvent += () => this.AnotherEvent.SafeInvoke();
as being equivalent. It seems they're not.
So what is the difference? Plus why is the event not being raised?
PS: while usually R# suggests to replace () => this.AnotherEvent.SafeInvoke(); by this.AnotherEvent.SafeInvoke it doesn't do so here. So apparently it knows that it should not do it here.
When you assign a method group to event like this:
this.rootEventSource.RootEvent += this.AnotherEvent.SafeInvoke;
you in fact create a delegate from method SignalExtensions.SafeInvoke which as a parameter takes your this.AnotherEventdelegate object. Since it is initially null, you create a delegate with null parameter. This null value will of course never change, since delegates are immutable.
If you want to forward an event you should maybe do it like this:
public class EventForwarder
{
private readonly RootEventSource rootEventSource;
public EventForwarder(RootEventSource rootEventSource)
{
this.rootEventSource = rootEventSource;
}
public event Signal AnotherEvent
{
add { this.rootEventSource.RootEvent += value; }
remove { this.rootEventSource.RootEvent -= value; }
}
}
I want to use event itself in my method. Is it possible?
Can "PlayWithEvent" method use "EventSource.Test" event as parameter?
public class EventSource
{
public event EventHandler Test;
}
class Program
{
static void Main(string[] args)
{
EventSource src = new EventSource ();
PlayWithEvent (src.Test);
}
static void PlayWithEvent (EventHandler e)
{
e (null, null);
}
}
I want a syntax something like that:
class Program
{
static void Main(string[] args)
{
EventSource src = new EventSource ();
PlayWithEvent (src.Test);
}
static void PlayWithEvent (event e)
{
e += something;
}
}
Your code won't compile—you can only access the EventHandler delegate for the event from within the same class as the event, and even then it would be null unless you actually add an event handler to call.
It is not currently working because you marked
public event EventHandler Test;
as an event.
Remove the event tag and try again. It now works for me. The reason for this are the restrictions that C# has for events... But in your code, all you want is a delegate. Declare your class as:
public class EventSource
{
public EventHandler Test;
}
Note that I removed event:
public EventHandler Test;
You can't do it like that. You need to pass the actual class.
public class EventSource
{
public event EventHandler Test;
public void TriggerEvent()
{
Test(this, EventArgs.Empty);
}
}
class Program
{
static void Main(string[] args)
{
EventSource src = new EventSource ();
PlayWithEvent (src);
}
static void PlayWithEvent (EventSource e)
{
src.TriggerEvent();
}
}
You can do it in a more generic way by introducing an interface:
public interface IEventPublisher<T> where T : EventArgs
{
public void Publish(T args);
}
public class EventSource : IEventPublisher<EventArgs>
{
public event EventHandler Test;
public void Publish(EventArgs args)
{
Test(this, args);
}
}
class Program
{
static void Main(string[] args)
{
EventSource src = new EventSource ();
PlayWithEvent (src);
}
static void PlayWithEvent (IEventPublisher<EventArgs> publisher)
{
publisher.Publish(EventArgs.Empty);
}
}
Only the class that an event is defined on can raise the event. If you need other classes to be able to manipulate it, you'll have to use a regular delegate.
Note, however, that since Test resolves to the underlying delegate when used within the scope of EventSource (as opposed to the externally accessible event), EventSource can pass it as a parameter to an external method.
I recently started digging into C# but I can't by my life figure out how delegates work when implementing the observer/observable pattern in the language.
Could someone give me a super-simple example of how it is done? I have googled this, but all of the examples I found were either too problem-specific or too "bloated".
The observer pattern is usually implemented with events.
Here's an example:
using System;
class Observable
{
public event EventHandler SomethingHappened;
public void DoSomething() =>
SomethingHappened?.Invoke(this, EventArgs.Empty);
}
class Observer
{
public void HandleEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happened to " + sender);
}
}
class Test
{
static void Main()
{
Observable observable = new Observable();
Observer observer = new Observer();
observable.SomethingHappened += observer.HandleEvent;
observable.DoSomething();
}
}
See the linked article for a lot more detail.
Note that the above example uses C# 6 null-conditional operator to implement DoSomething safely to handle cases where SomethingHappened has not been subscribed to, and is therefore null. If you're using an older version of C#, you'd need code like this:
public void DoSomething()
{
var handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
In this model, you have publishers who will do some logic and publish an "event."
Publishers will then send out their event only to subscribers who have subscribed to receive the specific event.
In C#, any object can publish a set of events to which other applications can subscribe.
When the publishing class raises an event, all the subscribed applications are notified.
The following figure shows this mechanism.
Simplest Example possible on Events and Delegates in C#:
code is self explanatory, Also I've added the comments to clear out the code.
using System;
public class Publisher //main publisher class which will invoke methods of all subscriber classes
{
public delegate void TickHandler(Publisher m, EventArgs e); //declaring a delegate
public TickHandler Tick; //creating an object of delegate
public EventArgs e = null; //set 2nd paramter empty
public void Start() //starting point of thread
{
while (true)
{
System.Threading.Thread.Sleep(300);
if (Tick != null) //check if delegate object points to any listener classes method
{
Tick(this, e); //if it points i.e. not null then invoke that method!
}
}
}
}
public class Subscriber1 //1st subscriber class
{
public void Subscribe(Publisher m) //get the object of pubisher class
{
m.Tick += HeardIt; //attach listener class method to publisher class delegate object
}
private void HeardIt(Publisher m, EventArgs e) //subscriber class method
{
System.Console.WriteLine("Heard It by Listener");
}
}
public class Subscriber2 //2nd subscriber class
{
public void Subscribe2(Publisher m) //get the object of pubisher class
{
m.Tick += HeardIt; //attach listener class method to publisher class delegate object
}
private void HeardIt(Publisher m, EventArgs e) //subscriber class method
{
System.Console.WriteLine("Heard It by Listener2");
}
}
class Test
{
static void Main()
{
Publisher m = new Publisher(); //create an object of publisher class which will later be passed on subscriber classes
Subscriber1 l = new Subscriber1(); //create object of 1st subscriber class
Subscriber2 l2 = new Subscriber2(); //create object of 2nd subscriber class
l.Subscribe(m); //we pass object of publisher class to access delegate of publisher class
l2.Subscribe2(m); //we pass object of publisher class to access delegate of publisher class
m.Start(); //starting point of publisher class
}
}
Output:
Heard It by Listener
Heard It by Listener2
Heard It by Listener
Heard It by Listener2
Heard It by Listener
.
.
.
(infinite times)
Here's a simple example:
public class ObservableClass
{
private Int32 _Value;
public Int32 Value
{
get { return _Value; }
set
{
if (_Value != value)
{
_Value = value;
OnValueChanged();
}
}
}
public event EventHandler ValueChanged;
protected void OnValueChanged()
{
if (ValueChanged != null)
ValueChanged(this, EventArgs.Empty);
}
}
public class ObserverClass
{
public ObserverClass(ObservableClass observable)
{
observable.ValueChanged += TheValueChanged;
}
private void TheValueChanged(Object sender, EventArgs e)
{
Console.Out.WriteLine("Value changed to " +
((ObservableClass)sender).Value);
}
}
public class Program
{
public static void Main()
{
ObservableClass observable = new ObservableClass();
ObserverClass observer = new ObserverClass(observable);
observable.Value = 10;
}
}
Note:
This violates a rule in that I don't unhook the observer from the observable, this is perhaps good enough for this simple example, but make sure you don't keep observers hanging off of your events like that. A way to handle this would be to make ObserverClass IDisposable, and let the .Dispose method do the opposite of the code in the constructor
No error-checking performed, at least a null-check should be done in the constructor of the ObserverClass
I've tied together a couple of the great examples above (thank you as always to Mr. Skeet and Mr. Karlsen) to include a couple of different Observables and utilized an interface to keep track of them in the Observer and allowed the Observer to to "observe" any number of Observables via an internal list:
namespace ObservablePattern
{
using System;
using System.Collections.Generic;
internal static class Program
{
private static void Main()
{
var observable = new Observable();
var anotherObservable = new AnotherObservable();
using (IObserver observer = new Observer(observable))
{
observable.DoSomething();
observer.Add(anotherObservable);
anotherObservable.DoSomething();
}
Console.ReadLine();
}
}
internal interface IObservable
{
event EventHandler SomethingHappened;
}
internal sealed class Observable : IObservable
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
var handler = this.SomethingHappened;
Console.WriteLine("About to do something.");
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
internal sealed class AnotherObservable : IObservable
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
var handler = this.SomethingHappened;
Console.WriteLine("About to do something different.");
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
internal interface IObserver : IDisposable
{
void Add(IObservable observable);
void Remove(IObservable observable);
}
internal sealed class Observer : IObserver
{
private readonly Lazy<IList<IObservable>> observables =
new Lazy<IList<IObservable>>(() => new List<IObservable>());
public Observer()
{
}
public Observer(IObservable observable) : this()
{
this.Add(observable);
}
public void Add(IObservable observable)
{
if (observable == null)
{
return;
}
lock (this.observables)
{
this.observables.Value.Add(observable);
observable.SomethingHappened += HandleEvent;
}
}
public void Remove(IObservable observable)
{
if (observable == null)
{
return;
}
lock (this.observables)
{
observable.SomethingHappened -= HandleEvent;
this.observables.Value.Remove(observable);
}
}
public void Dispose()
{
for (var i = this.observables.Value.Count - 1; i >= 0; i--)
{
this.Remove(this.observables.Value[i]);
}
}
private static void HandleEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happened to " + sender);
}
}
}
Applying the Observer Pattern with delegates and events in c# is named "Event Pattern" according to MSDN which is a slight variation.
In this Article you will find well structured examples of how to apply the pattern in c# both the classic way and using delegates and events.
Exploring the Observer Design Pattern
public class Stock
{
//declare a delegate for the event
public delegate void AskPriceChangedHandler(object sender,
AskPriceChangedEventArgs e);
//declare the event using the delegate
public event AskPriceChangedHandler AskPriceChanged;
//instance variable for ask price
object _askPrice;
//property for ask price
public object AskPrice
{
set
{
//set the instance variable
_askPrice = value;
//fire the event
OnAskPriceChanged();
}
}//AskPrice property
//method to fire event delegate with proper name
protected void OnAskPriceChanged()
{
AskPriceChanged(this, new AskPriceChangedEventArgs(_askPrice));
}//AskPriceChanged
}//Stock class
//specialized event class for the askpricechanged event
public class AskPriceChangedEventArgs : EventArgs
{
//instance variable to store the ask price
private object _askPrice;
//constructor that sets askprice
public AskPriceChangedEventArgs(object askPrice) { _askPrice = askPrice; }
//public property for the ask price
public object AskPrice { get { return _askPrice; } }
}//AskPriceChangedEventArgs
/**********************Simple Example ***********************/
class Program
{
static void Main(string[] args)
{
Parent p = new Parent();
}
}
////////////////////////////////////////////
public delegate void DelegateName(string data);
class Child
{
public event DelegateName delegateName;
public void call()
{
delegateName("Narottam");
}
}
///////////////////////////////////////////
class Parent
{
public Parent()
{
Child c = new Child();
c.delegateName += new DelegateName(print);
//or like this
//c.delegateName += print;
c.call();
}
public void print(string name)
{
Console.WriteLine("yes we got the name : " + name);
}
}
I did't want to change my source code to add additional observer , so I have written following simple example:
//EVENT DRIVEN OBSERVER PATTERN
public class Publisher
{
public Publisher()
{
var observable = new Observable();
observable.PublishData("Hello World!");
}
}
//Server will send data to this class's PublishData method
public class Observable
{
public event Receive OnReceive;
public void PublishData(string data)
{
//Add all the observer below
//1st observer
IObserver iObserver = new Observer1();
this.OnReceive += iObserver.ReceiveData;
//2nd observer
IObserver iObserver2 = new Observer2();
this.OnReceive += iObserver2.ReceiveData;
//publish data
var handler = OnReceive;
if (handler != null)
{
handler(data);
}
}
}
public interface IObserver
{
void ReceiveData(string data);
}
//Observer example
public class Observer1 : IObserver
{
public void ReceiveData(string data)
{
//sample observers does nothing with data :)
}
}
public class Observer2 : IObserver
{
public void ReceiveData(string data)
{
//sample observers does nothing with data :)
}
}
Something like this:
// interface implementation publisher
public delegate void eiSubjectEventHandler(eiSubject subject);
public interface eiSubject
{
event eiSubjectEventHandler OnUpdate;
void GenereteEventUpdate();
}
// class implementation publisher
class ecSubject : eiSubject
{
private event eiSubjectEventHandler _OnUpdate = null;
public event eiSubjectEventHandler OnUpdate
{
add
{
lock (this)
{
_OnUpdate -= value;
_OnUpdate += value;
}
}
remove { lock (this) { _OnUpdate -= value; } }
}
public void GenereteEventUpdate()
{
eiSubjectEventHandler handler = _OnUpdate;
if (handler != null)
{
handler(this);
}
}
}
// interface implementation subscriber
public interface eiObserver
{
void DoOnUpdate(eiSubject subject);
}
// class implementation subscriber
class ecObserver : eiObserver
{
public virtual void DoOnUpdate(eiSubject subject)
{
}
}
.
observer pattern C# with event
.
link to the repository