One handler for several events - c#

I have four events:
View.AdditionPerformed += new EventHandler<EventArgs>(OnOperationPerformed);
View.SubtractionPerformed+=new EventHandler<EventArgs>(OnOperationPerformed);
View.DivisionPerformed+=new EventHandler<EventArgs>(OnOperationPerformed);
View.MultiplyPerformed+=new EventHandler<EventArgs>(OnOperationPerformed);
and one method:
private void OnOperationPerformed(object sender, EventArgs e)
{
}
How can I define which event raised my method? Something like this:
private void OnOperationPerformed(object sender, EventArgs e)
{
switch(event)
{
case MultiplyPerformed:{}
case DivisionPerformed:{}
...
}
}

Write your own EventArgs which has an enum inside, telling you the raised event.
enum MyEventEnum
{
AdditionPerformed,
SubtractionPerformed,
DivisionPerformed,
MultiplayPerformed
}
The EventArgs
class MyEventArgs : EventArgs
{
public MyEventEnum EventRaised { get; set; }
}
Define the Handlers
View.AdditionPerformed += new EventHandler<MyEventArgs>(OnOperationPerformed);
View.SubtractionPerformed+=new EventHandler<MyEventArgs>(OnOperationPerformed);
View.DivisionPerformed+=new EventHandler<MyEventArgs>(OnOperationPerformed);
View.MultiplyPerformed+=new EventHandler<MyEventArgs>(OnOperationPerformed);
When you call them:
this.AdditionPerformed(this, new MyEventArgs
{ EventRaised = MyEventEnum.AdditionPerformed };
I know it's pretty hardcoded, but there isn't any other way.

Instead of using EventArgs, you could use your own event argument class to pass in the necessary data to make the choice inside the handler.
It would then become available on your e variable inside the handler.
Cheers

Related

Passing custom EventArgs as parameter of event

I am new to events and have been trying to create one and succeed but I have one question.
I have created event like this:
public class CustomControl : Panel
{
public event EventHandler OutputChanged; //My event
public CustomControl()
{
InitializeComponents();
}
//This event raises inside richtextbox which is inside my panel
private void OnTextChanged(object sender, EventArgs e)
{
if (OutputUpdate == OutputUpdate.OnTextChanged)
{
ValidateText();
//This is my created event
OnOutputChanged(new OutputChangedEventArgs { Asd = "Something" });
}
}
//void for this event
protected virtual void OnOutputChanged(OutputChangedEventArgs e)
{
EventHandler handler = OutputChanged;
if(handler != null)
{
handler(this, e);
}
}
}
//Custom event args class for my event
public class OutputChangedEventArgs : EventArgs
{
public string Asd { get; set; }
}
Above code shows declaration of my event with custom class for EventArgs parameter and now I will show you how I implement it in my code:
customControl1.OutputChanged += OnOutputChanged;
private void OnOutputChanged(object sender, EventArgs e)
{
OutputChangedEventArgs args = e as OutputChangedEventArgs;
MessageBox.Show(args.Asd);
}
As you can see in my implantation I pass EventArgs and then I convert it to OutputChangedEventArgs and reason for that is because if I try private void OnOutputChanged(object sender, OutputChangedEventArgs e) I get error No overload for 'OnOutputChanged' matches delegate 'EventHandler'
So my question is how can I directly pass my custom EventArgs class so I do not need to convert it inside method that handles it?
You can use the generic version of EventHandler that allows the specification of the argument type.
public event EventHandler<OutputChangedEventArgs> OutputChanged;

how can i add event args? if i add inside System.EventHandler( , ) i get an error

how can i add event args? if i add inside System.EventHandler( , ) i get an error.
class RadioButtonChecked: EventArgs
{
private int m_ButtonNumber;
public RadioButtonChecked(int num)
{
m_ButtonNumber = num;
}
public int ButtonNumber
{
get { return m_ButtonNumber; }
}
}
this.radioButton1.Click += new System.EventHandler(this.radioButton_CheckedChanged);
this.radioButton2.Click += new System.EventHandler(this.radioButton_CheckedChanged);
private void radioButton_CheckedChanged(object sender, RadioButtonChecked e)
{
//do something...
}
The signature of your handler should be:
private void radioButton_CheckedChanged(object sender, EventArgs e)
It should exactly match the signature that the Click event expects. You can still pass in your RadioButtonChecked (which by convention should be name RadioButtonCheckedEventArgs), since it derives from EventArgs. If you want to do something with the event in your handler, you can cast it back to RadioButtonChecked.

Detecting source of event and type of event using C#

I'm learning how to work with delegates and by now have got some ideas. In a C# code (below) I like to capture type of event in string. What is the best approach to get the source of event and type of event?
For name of the source I'm using sender.GetType().FullName.ToString(); if it is correct. What about event type?
Thanks.
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this,e);
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
OnChanged(EventArgs.Empty);
}
public EventListener(myForm theform)
{
TheForm = theform;
TheForm.Changed += new ChangedEventHandler(myMethod);
}
private void myMethod(object sender, EventArgs e)
{
string s = "hey, got notified " + sender.GetType().FullName.ToString();
MessageBox.Show(s);
}
There is no way to know which event call the function with the EventArgs class.
If you are using the prepared events (like Click event), you can create your own "Args" class like that:
public class MyEventArgs : EventArgs
{
public string EventCallerName { get; set; }
}
Then call the event like that:
if (Changed != null)
Changed(this,new MyEventArgs() { EventCallerName = "Changed" });
And in the receiver method you can see that value, like that:
private void myMethod(object sender, EventArgs e)
{
if (e is MyEventArgs)
MessageBox.Show("Event type: " + (e as MyEventType).EventCallerName);
string s = "hey, got notified " + sender.GetType().FullName.ToString();
MessageBox.Show(s);
}
But, if you are using your own event you can create your own delegate and do with it whatever you want.
You should be able to find the source of the event by using a StackTrace. I believe you'll find that events are usually fired by protected functions that have names that are similar to the event name.
Backing type for events is delegate. The event source from the event handler cannot be determined. You however can check the delegate type when you are subscribing to the event. The class defining\publishing the event will be event source and type of delegate will be event type.
May be that is right solution?:
private void Form1_FormClosed(object sender, EventArgs e)
{
var eventType = e.ToString().Split('.').Last().Replace("EventArgs", ""); //eventType = "FromClosed"
}
Assuming you want the name of the event, rather than detecting why don't you just fix it when you register the handler for the event? Something like:
public EventListener(myForm theform)
{
TheForm = theform;
TheForm.Changed += (s, e) => this.MyMethod(s, e, "Changed");
}
private void MyMethod(object sender, EventArgs e, string eventName)
{
string s = "hey, got notified " + sender.GetType().FullName.ToString();
MessageBox.Show(s);
}

Why can't I directly pass a custom event args class into a method subscribing to my event?

Why can't I directly pass custom event arguments into a method subscribing to my event even though my custom event args class directly inherits from EventArgs?
For example, consider the two below classes. One is the class I want to work with, the other inherits from EventArgs, and contains some additional information related to the event:
using System;
namespace ConsoleApplication11
{
class MyClass
{
public event EventHandler MyEvent;
public void MyMethod(int myNumber)
{
Console.WriteLine(myNumber);
if(myNumber == 7)
{
MyEvent.Invoke(null, new MyCustomEvent() { Foo = "Bar" });
}
}
}
class MyCustomEvent : EventArgs
{
public string Foo { get; set; }
}
}
So if a number 7 is passed into MyMethod, I want to invoke MyEvent passing in the a new instance of the MyCustomEvent class to any method subscribing to my event.
I subscribe to this from my main program like so:
using System;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.MyEvent += new EventHandler(myClass_MyEvent);
for (int i = 0; i < 9; i++)
{
myClass.MyMethod(i);
}
}
static void myClass_MyEvent(object sender, EventArgs e)
{
//Do Stuff
}
}
}
Even though I am passing in a MyCustomEvent object when invoking the event, if I change the second parameter in the method subscribing to my event to a MyCustomEvent object I get a compile error. I need to instead explicitly cast the EventArgs object to a MyCustomEvent before I can access any additional fields/methods etc inside the class.
When working with an object that has a lot of different events, each one having a unique related custom EventArgs class, keeping track of what the EventArgs in each method subscribing to each event needs to be casted to can get a bit messy.
It would be a lot easier if I could pass my custom EventArgs class directly into the methods subscribing to my event.
Is this a possibility?
Thanks
Instead of declaring your event as being of type EventHandler, create a new delegate that specifically uses your custom event args class:
public delegate void MyEventHandler(object sender, MyEventArgs args);
public event MyEventHandler MyEvent;
Now you can pass the arguments directly without casting.
The other option is to use the generic EventHandler<T>:
public event EventHandler<MyEventArgs> MyEvent;
I prefer the former, since you can then give the delegate type a more descriptive name, though the latter is a bit quicker.
Declare your event using generic version of EventHandler:
public event EventHandler<MyCustomEvent> MyEvent;
Rather than use a default event handler just define your own that fits the signature you are trying to achieve...
public delegate void MyEventHandler(object sender, MyCustomEventArgs e)
public event MyEventHandler MyEvent;
forgive me if i understood your question wrong. I'm a little confused by not seeing any custom EventArgs class.
You can't make a method signature like
static void myClass_MyEvent(object sender, CustomEventArgs e)
for an event that expects a
static void myClass_MyEvent(object sender, EventArgs e)
That is backwards polymorphism, and polymorphism doesn't work backwards.
let's say your event accesses a e.OnlyInCustomEventArgs, but is instead passed the base object, EventArgs. Then the contract has been broken.
Now what you can do is
static void myClass_MyEvent(object sender, EventArgs e)
{
CustomEventArgs cea = (CustomEventArgs)e;
}
Here is the full code for a correctly implemented custom arg event handler.
class MyClass
{
public event EventHandler<MyCustomEventArgs> MyEvent;
public void MyMethod(int myNumber)
{
Console.WriteLine(myNumber);
if (myNumber == 7)
{
MyEvent.Invoke(null, new MyCustomEventArgs() { Foo = "Bar" });
}
}
}
class MyCustomEventArgs : EventArgs
{
public string Foo { get; set; }
}
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.MyEvent += new EventHandler<MyCustomEventArgs>(myClass_MyEvent);
for (int i = 0; i < 9; i++)
{
myClass.MyMethod(i);
}
}
//This is the method signature that you need to use to handle the event
static void myClass_MyEvent(object sender, MyCustomEventArgs e)
{
Console.WriteLine(e.Foo); // prints "Bar"
//Do Stuff
}
//If you need to handle more than one type of custom event args
static void myClass_MyEvent<T>(object sender, T e) where T : EventArgs
{
//Do Stuff
}
}

How can I pass addition parameters to my centralized event handlers?

In a WPF application, I've got my events centralized in one class like this:
public class EventFactory
{
public static void Button_Edit_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("you clicked edit");
}
public static void Button_Add_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("you clicked add");
}
}
so that I can reuse them in many Windows like this:
public Window1()
{
InitializeComponent();
ButtonEdit.Click += EventFactory.Button_Edit_Click;
ButtonAdd.Click += EventFactory.Button_Add_Click;
}
This works fine, but now I want the events to act on the Windows which call them which I was able to do when the event handlers were simply in the code-behind for each window.
How can I e.g. inject a window object into the event handler so that that event handler can directly manipulate it, something like this:
ButtonEdit.Click += EventFactory.Button_Edit_Click(this);
One way:
ButtonEdit.Click += EventFactory.ForConsumer<Window1>().Button_Edit_Click;
In other words, turn your factory class into an actual factory that creates objects based on some context. In this case, the context is the object consuming the events.
Another way:
public static void Button_Edit_Click(object sender, RoutedEventArgs e)
{
Window window = Window.GetWindow(sender as DependencyObject);
MessageBox.Show("you clicked edit");
}
I'm not particularly fond of either of these approaches, but there you go.
You can try something like this:
public class CommonEventHandler
{
private CommonEventHandler() { }
private object Context { get; set; }
public static EventHandler CreateShowHandlerFor(object context)
{
CommonEventHandler handler = new CommonEventHandler();
handler.Context = context;
return new EventHandler(handler.HandleGenericShow);
}
private void HandleGenericShow(object sender, EventArgs e)
{
Console.WriteLine(this.Context);
}
}
class Program
{
static void Main(string[] args)
{
EventHandler show5 = CommonEventHandler.CreateShowHandlerFor(5);
EventHandler show7 = CommonEventHandler.CreateShowHandlerFor(7);
show5(null, EventArgs.Empty);
Console.WriteLine("===");
show7(null, EventArgs.Empty);
}
}
You need to adapt the types to suit your needs but it shows the general idea.

Categories