I have a class library that has a number of classes.
Any of these classes should be able to send a message (string) to the client at any point of time . I want to have a Generic Event that can be raised from a number of classes. I don't want a separate event for each class.
Something like this:
public class GenericEvent
{
// Here I have an event.
}
public class LibClass1
{
//Raise event here.
}
public class LibClass2
{
//Raise event here
}
public class Client
{
//Subscribe to the event here
}
Is this the right approach? If yes, how can it be achieved? The examples I looked up all have a separate event for each class.
It depends on what this event is and use cases, but one of the options is to use inheritance:
public class GenericEvent
{
// Here I have an event.
protected void RaiseEvent();
}
public class LibClass1 : GenericEvent
{
public voidDoSomethingAndRaiseEvent()
{
// ...
RaiseEvent();
}
}
This is how INotifiPropertyChanged is usually implemented.
If inheritance is impossible and you're using aggregation, LibClass1 and LibClass2 should act as some facade/decorator for GenericEvent: they must have their own event, which re-directs calls to GenericEvent's event and method(-s) to raise it:
public class GenericEvent
{
public event EventHandler SomeEvent;
// ...
}
public class LibClass1
{
private readonly GenericEvent _ge;
// ...
public event EventHandler SomeEvent
{
add { _ge.SomeEvent += value; }
remove { _ge.SomeEvent -= value; }
}
public void DoSomethingAndRaiseEvent()
{
// ...
SomeEvent?.Invoke(this, EventArgs.Emtpy);
}
}
public class MyEventArgs : EventArgs
{
// class members
}
public abstract class Lib
{
public event EventHandler ShapeChanged;
public virtual void OnShapeChanged(MyEventArgs e)
{
if (ShapeChanged != null)
{
ShapeChanged(this, e);
}
}
}
public class LibClass1 : Lib
{
//Raise event here.
}
public class LibClass2 : Lib
{
//Raise event here
}
static void Main(string[] args)
{
LibClass1 lib1 = new LibClass1();
LibClass2 lib2 = new LibClass2();
lib1.ShapeChanged += Lib1_ShapeChanged;
lib2.ShapeChanged += Lib1_ShapeChanged;
lib1.OnShapeChanged(new MyEventArgs());
}
Here full example create an abstract class in which you have the event.
I would work with inheritance. For example:
public class ParentClass : Form
{
public ParentClass() {
this.FormClosed += sendString;
}
private void sendString(object sender, FormClosedEventArgs e)
{
throw new NotImplementedException();
}
}
public class GenericEvent : ParentClass { }
public class LibClass1 : ParentClass { }
public class LibClass2 : ParentClass { }
public class Client : ParentClass { }
Now all of you Clases have the event of the ParentClass.
I have another approach.
Derive all of your classes from one single base class. (of course any library do that, .net or MFC or Qt or java framework).
you have a single event "event 1" in base class. In that event1 handler, raise "event 2".
Subscribe all your child classes to the "event2" of parent class and handle your business in respective child classes.
Related
I have a class with an EventHandler for TimeChanged. A couple of instances of this class are created. In one of the instances of the class, the time can be changed. I would like all instances to react to the event of changed time.
Example:
public class MainClass
{
public MainClass()
{
}
public event EventHandler TimeChanged;
private virtual void OnTimeChanged()
{
EventHandler handler = TimeChanged;
if(handler != null)
{
handler(this, eventArgs.Empty);
}
}
}
public class AnotherClass
{
public AnotherClass()
{
MainClass _mainClass = new MainClass();
}
private void OnLoaded()
{
_mainClass.TimeChanged += HandleTimeChanged;
}
private void HandleTimeChanged
{
//Some stuff happens with new time, etc.
}
}
public class TimeClass
{
MainClass _class = new MainClass();
TimeSpan _timeValue;
private void ChangeTime()
{
// This is where the _timeValue is changed
// All instances of MainClass, subscribed to TimeChanged event to be notified with the new value selected.
}
}
So, basically when I change the time in TimeClass, which contains an instance of MainClass, I want to fire the TimeChanged event and all instances of MainClass (like in AnotherClass) should respond to the TimeChanged event to which they subscribed.
Hope this explains the situation. Any suggestions are welcome. Thanks.
Suppose I have the following Interface:
interface IBook
{
event EventHandler<EventArgs> PageChanged;
}
which I could implement without difficulty for this class:
class Novel : IBook
{
public event EventHandler<EventArgs> PageChanged;
protected void OnPageChanged()
{
EventHandler<EventArgs> pageChanged = PageChanged;
if (pageChanged != null) pageChanged(this, EventArgs.Empty);
}
}
however, if I now have an object called Encyclopedia defined as:
class Encyclopedia : IBook
{
public class EncyclopediaEventArgs : EventArgs
{
public int Volume
{
get { return volume; }
}
private int volume;
public EncyclopediaEventArgs(int volume)
{
this.volume = volume;
}
}
public event EventHandler<EncyclopediaEventArgs> PageChanged;
protected void OnPageChanged(int volume)
{
EventHandler<EncyclopediaEventArgs> pageChanged = PageChanged;
if (pageChanged != null) pageChanged(this, new EncyclopediaEventArgs(volume));
}
}
which has all the workings of a Book, but with the added event argument field of Volume. When I compile, I get an error (as surmised I would):
error CS0738: 'Encyclopedia' does not implement interface member 'IBook.PageChanged'. 'Encyclopedia.PageChanged' cannot implement 'IBook.PageChanged' because it does not have the matching return type of 'System.EventHandler'
It states that it cannot implement IBook.PageChanged because System.EventHandler<System.EventArgs> is not the return type, even though EncyclopediaEventArgs derives from System.EventArgs.
My question, therefore, is, would it be possible to derive such a class as Encyclopedia which adds the additional Volume field to its event arguments?
(Any discussion is very much welcome as to why this is or is not a poor design/architecture decision!)
It seems fairly straight forward to do this:
interface IBook<T> where T : EventArgs
{
event EventHandler<T> PageChanged;
}
class Novel : IBook<EventArgs> { ... }
class Encyclopedia : IBook<Encyclopedia.EncyclopediaEventArgs> { ... }
If you still need a plain IBook then you would do this:
interface IBook { }
interface IBook<T> : IBook where T : EventArgs
{
event EventHandler<T> PageChanged;
}
It depends a bit on how you are going to use IBook. You could create a generic parameter for the EventArgs like so:
public interface IBook<TEventArgs> where TEventArgs : EventArgs
{
event EventHandler<TEventArgs> PageChanged;
}
public class Novel : IBook<EventArgs>
{
event EventHandler<EventArgs> PageChanged;
}
public class Encyclopedia : IBook<EncyclopediaEventArgs>
{
event EventHandler<EncyclopediaEventArgs> PageChanged;
}
But then you can't use IBook without the generic type if you need PageChanged for other purposes.
Another way is to just keep the event EventHandler<EventArgs> PageChanged; have the Encyclopedia implementation pass a EncyclopediaEventArgs and just cast in the event handler.
class Encyclopedia : IBook
{
public class EncyclopediaEventArgs : EventArgs
{
}
public event EventHandler<EventArgs> PageChanged;
protected void OnPageChanged(int volume)
{
EventHandler<EventArgs> pageChanged = PageChanged;
if (pageChanged != null) pageChanged(this, new EncyclopediaEventArgs(...));
}
}
public class BookReader
{
public void OnPageChanged(object sender, EventArgs e)
{
if (sender is Encyclopedia && e is EncyclopediaEventArgs)
{
EncyclopediaEventArgs ee = (EncyclopediaEventArgs)e;
}
else
{
}
}
}
Not very familiar with declaring and using events and received error,
Event must be of delegate type
Basically want to pass IMyInterface as a dependency to another class where that class can subscribe to receive MyClassEvent events and the event data is MyClass.
public interface IMyInterface
{
event MyClass MyClassEvent;
}
public class Implementation: IMyInterface
{
event MyClass MyClassEvent;
public void OnSomethingHappened
{
MyClassEvent?.Invoke(); // pass MyClass to subscribers
}
}
public class AnotherClass(IMyInterface ...)
{
OnMyClassEvent(MyClass args)
{
// do something
}
}
You need to declare the event correctly and define the event args:
public class MyClassEventArgs : EventArgs { }
public interface IMyInterface
{
event EventHandler<MyClassEventArgs> MyClassEvent;
}
public class Implementation : IMyInterface
{
public event EventHandler<MyClassEventArgs> MyClassEvent;
public void OnSomethingHappened()
{
MyClassEvent?.Invoke(this, new MyClassEventArgs());
}
}
And to subscribe to it:
var implementation = new Implementation();
implementation.MyClassEvent += MyClassEvent;
private void MyClassEvent(object sender, MyClassEventArgs e) { ... }
My interface has an event that don't has an arguments
public interface IMyInterface
{
event EventHandler OnSomethingHappened;
}
Here is how I am implementing it.
public class MyBaseClass : IMyInterface
{
private event EventHandler onSomethingHappened;
public event EventHandler OnSomethingHappened
{
add
{
onSomethingHappened-= value;
onSomethingHappened+= value;
}
remove
{
onSomethingHappened-= value;
}
}
}
But somehwere else when I try to use it as follows
if ( MyBaseClassInstance.OnSomethingHappened != null )
MyBaseClassInstance.OnSomethingHappened();
I get following compilation error
The event 'ConsoleApplication1.IMyInterface.OnSomethingHappened' can
only appear on the left hand side of += or -=
What am I doing wrong?
This is how your code might look:
public interface IMyInterface
{
event EventHandler OnSomethingHappened;
}
//implement the interface
public class MyBaseClass : IMyInterface
{
public event EventHandler OnSomethingHappened;
public void DoSomeLogicWhichRaisesTheEvent()
{
if (OnSomethingHappened != null)
{
MyBaseClass sender = this;
var eventArgs = new EventArgs();
//let all subscibers to event know that the event happened
OnSomethingHappened(sender, eventArgs);
}
}
}
public class ConsumerClass
{
private IMyInterface myBaseClassInstance;
public ConsumerClass()
{
myBaseClassInstance = new MyBaseClass();
//attach to the event
myBaseClassInstance.OnSomethingHappened += MyBaseClassInstance_OnSomethingHappened;
}
private void MyBaseClassInstance_OnSomethingHappened(object sender, EventArgs e)
{
//react to the raised event
throw new NotImplementedException();
}
}
As you can see you need to implement the IMyInterface interface, and when MyBaseClass needs to raise the event you call OnSomethingHappened(sender, eventArgs);
ConsumerClass is where you need to consume, or to do something, as a reaction to the raised event.
You may consider to rename MyBaseClass to some other name, without 'Base' in it, because it is not an abstract class.
I am creating a gui widget a dll library, a class that derives from a FORM (I thought about usercontrol but it doesn't have built in properties like Opacity and some more that i need).
Because I don't want to expose to the user of this control all the standard methods and propertis that this derived class will inherit, I've created a nothe class "middle-man" that should encapsulate and expose only the needed methos to the user of this dll.
The problem is exposing the events.
This is an abstract example:
class Class1
{
Class2 theClass2;
public Class1()
{
theClass2 = new Class2();
theClass2. += new EventHandler(theClass3_EventHandler);
theClass2.TriggerEvent();
}
void theClass3_EventHandler(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
class Class2
{
Class3 theClass3;
public Class2()
{
theClass3 = new Class3();
}
public void TriggerEvent()
{
theClass3.Trigger();
}
class Class3
{
public event EventHandler theEvent;
public void Trigger()
{
if (this.theEvent != null)
theEvent(this, new EventArgs());
}
}
}
public event EventHandler theEvent {
add {
SomeNestedClass.theEvent += value;
}
remove {
SomeNestedClass.theEvent -= value;
}
}
First of all, inheritance is a is-a relationship. That means that everything that a Form can do should all sub classes be able to do. Since this is not the case for you, you should not derive the form.
As for the events. You need to redefine them in your "middle-man" class. And in that class simply subscribe on the events from the form and trigger them in the handler methods.
public class MyCoolControl : Control
{
private Form _customForm;
public MyCoonControl()
{
_customForm.Clicked += (source, e) => Clicked(source,e);
}
public event EventHandler Clicked = delegate {};
}