how to set up eventhandler - c#

with the code posted below I want to update progressbar from foo1.
but I'm unable to implement eventhandler in Foo
class Foo : Form // implements progressbar
{
IFoo foo = new Foo1()
// this will not do:
ProgressBarEventHandler = new EventUpdateProgressBar(this.UpdateProgressBar);
UpdateProgressBar() { }
}
public delegate void EventUpdateProgressBar();
class FooBase
{
public EventUpdateProgressBar ProgressBarEventHandler;
protected virtual void UpdateProgressBar()
{
if (ProgressBarEventHandler != null)
ProgressBarEventHandler();
}
}
class Foo1 : IFoo,FooBase { base.UpdateProgressBar() }
class Foo2 : IFoo,FooBase {}
interface IFoo {}
is there a way to get this working or is there a better approach ?

I'm not completely sure what your intent was, but if you're trying to implement two classes, one of which raises events while the other handles them, then the minimal sample would look as follows.
delegate void MyEvent();
class MyEventSource
{
public event MyEvent Event;
public void RaiseEvent()
{
MyEvent evt = Event;
if (evt != null)
evt();
}
}
class MyEventListener
{
public void SubscribeForEventFromMyEventSource(MyEventSource eventSource)
{
eventSource.Event += this.EventHandler;
}
public void EventHandler()
{
// Event handling logic here
}
}
More reading on events is available here: https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx and here https://codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/

Related

Collection of generic handlers - is this possible?

Using generics is it possible to have a generic collection defined as a base type and assign instances of a sub type? I have a simple code sample below that highlights my thinking and the line that causes the compiler error. I know that I could create a IEventHandler marker interface and make my generic event handlers inherit from that. This would let me store the generic types within a collection of IList, but this seems less than ideal. Is there a way similar to the code I have below?
using System;
using System.Collections.Generic;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
IEventHandler<SomeEvent1> handler1 = new SomeEvent1Handler();
IEventHandler<SomeEvent2> handler2 = new SomeEvent2Handler();
IList<IEventHandler<IEvent>> handlers = new List<IEventHandler<IEvent>>();
// COMPILE ERROR - is this possible?
handlers.Add(new SomeEvent1Handler());
}
public interface IEvent {
}
public interface IEventHandler<in TEvent> where TEvent : IEvent
{
void Handle(TEvent someEvent);
}
public class SomeEvent1 : IEvent {
}
public class SomeEvent2 : IEvent {
}
public class SomeEvent1Handler : IEventHandler<SomeEvent1>
{
public void Handle(SomeEvent1 someEvent)
{
throw new NotImplementedException();
}
}
public class SomeEvent2Handler : IEventHandler<SomeEvent2>
{
public void Handle(SomeEvent2 someEvent)
{
throw new NotImplementedException();
}
}
}
}
Using generics is it possible to have a generic collection defined as
a base type and assign instances of a sub type?
Yes, but It could only be done if your interface was IEventHandler<out TEvent>, you can't do it with in.
If your code did work, what would you expect to happen if the code was
public static void Main(string[] args)
{
IList<IEventHandler<IEvent>> handlers = new List<IEventHandler<IEvent>>();
handlers.Add(new SomeEvent1Handler()); //Magicly works
IEventHandler<IEvent> handler = handlers[0];
handler.Handle(new SomeEvent2());
}
handler states it allows any IEvent to be passed in to its Handle function. This would cause SomeEvent1Handler would be passed a SomeEvent2 object to its public void Handle(SomeEvent1 someEvent) method.
My work around would be have the handlers just take in a IEvent, in the function they check if it is a type of event they don't care about they can just return from the function without doing anything.
using System;
using System.Collections.Generic;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
IEventHandler<SomeEvent1> handler1 = new SomeEvent1Handler();
IEventHandler<SomeEvent2> handler2 = new SomeEvent2Handler();
IList<IEventHandler> handlers = new List<IEventHandler>();
handlers.Add(new SomeEvent1Handler());
}
public interface IEvent {
}
public interface IEventHandler
{
void Handle(IEvent someEvent);
}
public class SomeEvent1 : IEvent {
}
public class SomeEvent2 : IEvent {
}
public class SomeEvent1Handler : IEventHandler
{
public void Handle(IEvent someEvent)
{
var event = someEvent as SomeEvent1;
if(event == null)
return;
//Do stuff here.
}
}
public class SomeEvent2Handler : IEventHandler
{
public void Handle(IEvent someEvent)
{
var event = someEvent as SomeEvent2;
if(event == null)
return;
//Do stuff here.
}
}
}
}
This cannot be done as it is not safe - if it were allowed you could do:
var handlers = new List<IEventHandler<IEvent>> { new SomeEvent1Handler() };
handlers[0].Handle(new SomeEvent2());
I suggest you create a wrapper class around a typed handler e.g.
public class HandlerWrapper<T> : IEventHandler<IEvent>
{
private readonly IEventHandler<T> inner;
public HandlerWrapper(IEventHandler<T> inner)
{
this.inner = inner;
}
public void Handle(IEvent event)
{
if(event is T) { inner.handle((T)event); }
else throw new ArgumentException("Unexpected event type");
}
}
You can now create an IList<EventHandler<IEvent>> and you will need to manage the dispatch to the correct handler dynamically.

Event handler inheritance

I have a parent class that is firing an event to derived classes. The problem is that the event handler is alway null.
Class Plugin()
{
public delegate void BufferReadyHandler(string str);
public event BufferReadyHandler OnBufferReady;
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
protected void Sp_DataReceived_Parent(object sender, SerialDataReceivedEventArgs e)
{
strCommonBuffer += serial.ReadExisting();
if (strCommonBuffer.Contains("\r\n"))
{
if (OnBufferReady != null) <<-------NULL
OnBufferReady(strCommonBuffer);
strCommonBuffer = string.Empty;
}
}
}
then there are some derived classes that are linked to that event:
class ClassIO : ClassPlugin
{
public ClassIO(eGuiType _guyType) : base(_guyType)
{
...
OnBufferReady += ClassIO_OnBufferReady;
}
private void ClassIO_OnBufferReady(string str)
{
...
}
}
the problem is that the OnBufferReady event in the parent class is alway null and therefore never fired.
Thanks for any help.
I might be wrong but have you thought about making the event static?
public delegate void BufferReadyHandler(string str);
public static event BufferReadyHandler OnBufferReady;
I am not sure why you are having this problem, I suspect it has something to do with the code you have not shown us. However in this situation I would not have the child subscribe to the event at all, instead make a protected method that raises the event that the child can override.
Here is how I would implement the class.
public class BufferReadyEventArgs : EventArgs
{
public BufferReadyEventArgs(string commonBuffer)
{
CommonBuffer = commonBuffer;
}
public string CommonBuffer {get; private set;}
}
Class Plugin()
{
public event EventHandler<BufferReadyEventArgs> OnBufferReady;
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
protected void Sp_DataReceived_Parent(object sender, SerialDataReceivedEventArgs e)
{
strCommonBuffer += serial.ReadExisting();
if (strCommonBuffer.Contains("\r\n"))
{
RaiseOnBufferReady(strCommonBuffer);
strCommonBuffer = string.Empty;
}
}
protected virtual void RaiseOnBufferReady(string commonBuffer)
{
var temp = OnBufferReady;
if(temp != null)
temp(this, new BufferReadyEventArgs(commonBuffer));
}
}
class ClassIO : ClassPlugin
{
public ClassIO(eGuiType _guyType) : base(_guyType)
{
...
}
protected override void RaiseOnBufferReady(string commonBuffer)
{
base.RaiseOnBufferReady(commonBuffer);
...
}
}
Here is a working example based on your code:
using System;
using System.Collections.Generic;
public class MyClass
{
public static void Main()
{
ClassIO c = new ClassIO();
c.DataReceived();
Console.ReadLine();
}
}
public class ClassPlugin
{
public delegate void BufferReadyHandler(string str);
public event BufferReadyHandler OnBufferReady;
public ClassPlugin()
{
}
public void DataReceived()
{
if (OnBufferReady != null) {
OnBufferReady("Calling OnBufferReady");
}
}
}
public class ClassIO : ClassPlugin
{
public ClassIO() : base()
{
OnBufferReady += ClassIO_OnBufferReady;
}
private void ClassIO_OnBufferReady(string str)
{
Console.WriteLine("Inside ClassIO_OnBufferReady");
}
}
I don't understand why you would like to work with events in the first place for communication between parent and derived class.
If you need this communication, you would be better of with an (abstract) method in your base class that you implement in your derived classes.
If you need communication to all instances of derived types, you should look into composition instead of inheritance. Make some sort of manager instance that holds references to a list of instances of that base type and invokes a certain method on each of them in case of an 'event'.

Need an OOP Trick

I want an abstract class that raises an event, this event will be raised by the concrete class.
What I want is when I use another class to listen to these events the signature of the delegate should have the concrete type not the abstract, I don't want to cast it.
For the moment I have come up with this solution. It works but I don't find it particularly clever especially because of the "STUPID, DOESN'T MAKE SENSE......" part.
Here is my solution :
public delegate void ClassAEventHandler<TClassA>(TClassA classA) where TClassA : ClassA;
//Abstract class that raise Event
public abstract class ClassA<TClassA> : where TClassA : ClassA
{
public event ClassAEventHandler<TClassA> onClassEventRaised;
private TClassA eventClassA;
public void registerEventClass(TClassA classA)
{
this.eventClassA = classA;
}
public void raiseClassEvent()
{
this.onClassEventRaised(this.eventClassA);
}
}
// Exemple of concrete type
public class ClassB : ClassA<ClassB> // <------ IT SEEMS DUMB
{
public void action()
{
//Do something then raise event
this.raiseClassEvent();
}
public void saySomething() {};
}
// Exemple of concrete type
public class ClassC : ClassA<ClassC> // <------ IT SEEMS DUMB
{
public void command()
{
//Do something then raise event
this.raiseClassEvent();
}
public void destroySomething() {};
}
//Class that listen to the event raised
public class MyEventListener
{
private ClassB classB;
private ClassC classC;
public MyEventListener()
{
this.classB = new ClassB();
this.classB.registerEventClass(this.classB); // <------ STUPID, DOESN'T MAKE SENSE......
this.classB.onClassEventRaised += classB_onClassEventRaised;
this.classC = new ClassC();
this.classC.registerEventClass(this.classC); // <------ STUPID, DOESN'T MAKE SENSE......
this.classC.onClassEventRaised += classC_onClassEventRaised;
}
public void classB_onClassEventRaised(ClassB classB)
{
classB.saySomething();
}
public void classC_onClassEventRaised(ClassC classC)
{
classC.destroySomething();
}
//What i don't want
/*
public void classB_onClassEventRaised(ClassA classA)
{
((classB)classA).saySomething();
}
*/
}
First of all, you're not following regular event design in .NET.
Instead of implementing your own delegate, use EventHandler<TArgs>, and create a derived class of EventArgs.
Your CustomEventArgs should have a T generic parameter:
public class CustomEventArgs<T> where T : A
{
private readonly T _instance;
public CustomEventArgs(T instance)
{
_instance = instance;
}
public T Instance { get { return _instance; } }
}
Also, don't implement a custom way of registering events. If you want to encapsulate how handlers are added to the event, you need to use event accessors.
Finally, you could implement your classes as follows:
public class A<T> where T : A
{
private event EventHandler<CustomEventArgs<T>> _someEvent;
// An event accessor acts like the event but it can't be used
// to raise the event itself. It's just an accessor like an special
// event-oriented property (get/set)
public event EventHandler<CustomEventArgs<T>> SomeEvent
{
add { _someEvent += value; }
remove { _someEvent -= value; }
}
protected virtual void RaiseSomeEvent(CustomEventArgs<T> args)
{
// If C# >= 6
_someEvent?.Invoke(this, args);
// Or in C# < 6
// if(_someEvent != null) _someEvent(this, args);
}
}
public class B : A<B>
{
public void DoStuff()
{
// It's just about raising the event accessing the whole
// protected method and give an instance of CustomEventArgs<B>
// passing current instance (i.e. this) to CustomEventArgs<T>
// constructor.
RaiseSomeEvent(new CustomEventArgs<B>(this));
}
}
Now, if you try to handle SomeEvent, you'll get the CustomEventArgs<B> typed as B instead of A:
B b = new B();
b.SomeEvent += (sender, args) =>
{
// args.Instance is B
B instance = args.Instance;
};
b.DoStuff(); // Raises SomeEvent internally

Call an event from a base class

I have the following scenario:
public abstract class SomeBaseClass
{
public event EventHandler SomeEvent;
...
}
public class SomeClass : SomeBaseClass
{
public void DoSomething()
{
//TODO
if (SomeEvent != null)
SomeEvent(this, EventArgs.Empty);
}
}
SomeBaseClass has an event which needs to be called in a base class, however this it isn't possible to directly call the event from a base class. To get around this, I can override the event in the base class, like so:
public class SomeClass : SomeBaseClass
{
new public event EventHandler SomeEvent;
This is fine I guess, however my question is whether there is some kind of universal method, or good practice for implementing the functionality above?
The fact that it isn't possible to call an event from a base class suggests that I shouldn't really be doing this in the first place, perhaps the responsibility of calling the event should be only in SomeBaseClass?
That isn't allowed indeed. If I may recommend an alternative approach:
public abstract class SomeBaseClass
{
public event EventHandler SomeEvent;
protected void RaiseSomeEvent(EventArgs e)
{
var eh = SomeEvent;
if (eh != null)
eh(this, e);
}
}
public class SomeClass : SomeBaseClass
{
public void DoSomething()
{
//TODO
RaiseSomeEvent(EventArgs.Empty);
}
}
Note that I have moved the invocation of the event handler to the owning class, this is required by .NET / C# since only that class can invoke the event handler. Second, I have made the event handler thread safe by assigning it to eh first.
Never hide the base class' event by using the new keyword! You will get unexpected results when you use the base class' type as type for a variable or when the base class invokes the event.
I would stay away from using new mainly because code will behave differently if an object is cast to the base class. Here's an alternative implementation:
public abstract class SomeBaseClass
{
public virtual event EventHandler SomeEvent;
protected virtual void HandleSomeEvent()
{
var ev = SomeEvent; // Localize event field used
if (ev != null)
{
ev(this, EventArgs.Empty);
}
}
}
public class SomeClass : SomeBaseClass
{
public override event EventHandler SomeEvent
{
add { base.SomeEvent += value; }
remove { base.SomeEvent -= value; }
}
protected override void HandleSomeEvent()
{
base.HandleSomeEvent();
// ... My own code here
}
}
This allows for a great deal of flexibility. You can provide some implementation of event handling as well as allow the implementer to completely override the base class implementation.
public delegate void ErrorHandler(string result);
public class BaseClass
{
public event ErrorHandler OnError;
protected void RaiseErrorEvent(string result)
{
OnError?.Invoke(result);
}
}
public class SampleClass:BaseClass
{
public void Error(string s)
{
base.RaiseErrorEvent(s);
}
}
I personally prefer to use delegates for that :
public abstract class SomeBaseClass
{
public event EventHandler SomeEvent;
protected Action<object, EventArgs> SomeEventInvoker;
public SomeBaseClass()
{
SomeEventInvoker = new Action<object, EventArgs>((sender, args) =>
{ if (SomeEvent != null) SomeEvent(sender, args); });
}
}
public class SomeClass : SomeBaseClass
{
public SomeClass()
{
DoSomething();
}
public void DoSomething()
{
SomeEventInvoker(this, new EventArgs());
}
}

Using eventhandlers that are not in the current context

Is it possible to set, on a control (a linkbutton for example) an eventhandler which is not in the same context as the control creation?
For example, I have an instance of Class1 which instances Class2, the control is created in Class2, but I need the eventhandler to be in Class1.
Pseudo Code:
public class Class1
{
public Class1()
{
Class2 MyClass2 = new Class2();
MyClass2.DoSomething();
}
public void EventHandler()
{
// Handle the event
}
}
public class Class2
{
public void DoSomething()
{
SomeControl control = new SomeControl();
control.SomeEvent += parent.EventHandler;
}
}
Regards
Moo
Have your Class2 expose a custom public event. This event is triggered when the control event fires.
// In Class2
public event EventHandler<EventArgs<T>> ControlClickedEvent = null;
protected void OnControlClickedEvent()
{
if (ControlClickedEvent != null)
{
ControlClickedEvent(this, new EventArgs());
}
}
...
private void cmdButton_Click(object sender, EventArgs e)
{
OnControlClickedEvent();
}
Then have your Class1 subscribe to that event. The "event handler" is part of Class1.
// In Class1
MyClass2.ControlClickedEvent += new EventHandler<EventArgs<ControlClickedEvent>>(EventHandler);
If you are using multiple threads, ensure you use the InvokeRequired and BeginInvoke / Invoke methods in the code of the eventhandler in Class1.
Modifying darin's code:
public class Class1
{
public Class1()
{
Class2 class2 = new Class2();
class2.Control.SomeEvent += this.EventHandler;
}
public EventHandler()
{
//DoStuff
}
}
public class Class2
{
public Control control;
}
I have fallen out of favor of using straight events in C# these days for most communication like this. I prefer a more decoupled communication pattern, like the "Event Aggregator" which has many benefits over traditional event hooking. They include:
Reduced coupling (Class1 and Class2
don't need to know about each other)
Reduced event storms
Weak hookups (no memory leaks if you
forget to disconnect)
Filtering
public class Class1
{
public Class1()
{
new Class2().CreateControl(EventHandler);
}
public void EventHandler() {}
}
public class Class2
{
public void CreateControl(Action eventHandler)
{
SomeControl control = new SomeControl();
control.SomeEvent += eventHandler;
}
}

Categories

Resources