I'm often encountering a situation where I must decide where to subscribe to events of the inner object?
For example, I have an object model looks like this:
class ClassA
{
public event EventHandler SomeEvent1;
public event EventHandler SomeEvent2;
public event EventHandler SomeEvent3;
public event EventHandler SomeEvent4;
}
class ClassB
{
private ClassA a;
public ClassA A
{
get
{
return this.a;
}
}
public ClassB()
{
this.a = new ClassA();
// here subscribe to some events (for example, SomeEvent1 and SomeEvent2)
// this.a.SomeEvent1 += OnSomeEvent1Raised;
// this.a.SomeEvent2 += OnSomeEvent2Raised;
}
}
class ClassC
{
public ClassB B { get; }
}
class ClassD
{
public ClassC C { get; }
public void SomeMethod()
{
// Here subscribe to another ones events of object C.B.A. For example:
C.B.A.SomeEvent3 += OnSomeEvent3Raised;
C.B.A.SomeEvent4 += OnSomeEvent4Raised;
}
private void OnSomeEvent4Raised(object sender, EventArgs e)
{
throw new NotImplementedException();
}
private void OnSomeEvent3Raised(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
I've tried to create something like a UML diagram:
Structure of existing code of my project has places where such object model exist (its has a places where subscribing to events implemented as in the example above - C.B.A.SomeEvent+= ).
I don't like it and want to change it.
I want to here from you the best practices about this situation.
Alternative approach is to duplicate all events of classA in the classB, classC, classD.
And then replace all subscriptions to events to ONE PLACE (I mean that in the classB we will subscribe/unsubscribe to all events of the object of ClassA. In the classC we will subscribe/unsubscribe to all events of the object of classB. And so on...) In this case all subscriptions and unsubscriptions will be in one place. Hope, you understand what I mean here.
Again, please rely on your knowledge and experience tell we how to resolve this situation.
UPDATE
Do you agree with me that subscriptions and unsubscriptions to events must be placed in ONE PLACE ?
Please, answer on this additional question too.
Thanks in advance.
You might be interested in an event aggregator.
What it basically does is decoupling the publishers from subscribers - it's kind of a event container. You could get the event aggregator through dependency injection (e.g. MEF) for each class you'd like to subscribe or publish from.
The way I personally use and like it the most, is the way Rob Eisenberg implemented the event aggregator in Caliburn Micro:
NuGet Gallery
Caliburn.Micro Event Aggregator Documentation
In your case object A, B and C would share the same instance of an event aggregator, which means as soon as events are published on this event aggregator, all these objects recognize it. Class A, B and C are able behave differently, caused by different handling of certain events.
EDIT
The use of an event aggregator is, that you subscribe to the aggregator itself with an instance of a class. The connection between publisher and subscriber class happens through relying to the same instance of the event aggregator. In case of Caliburn.Micro subscription to certain events happens through implementing a generic interface (IHandle<>).
For example: if you'd like to subscribe to MyCustomEvent you implement the IHandle<MyCustomEvent> interface in the class to be subscribed.
This requires an implementation of the void Handle(MyCustomEvent e) method from the IHandle<MyCustomEvent> interface for this type of event. This method gets called everytime a (new) MyCustomEvent is published on the shared event aggregator.
There is way too much public stuff in your example. Hope I'll make sense below:
ClassB contains an object of type ClassA, and handles some ClassA events
ClassC contains an object of type ClassB but events are ignored.
ClassD contains an object of type ClassC and handles events from the ClassA object inside the ClassB object contains in this ClassC objects
#2 and #3 are not good: ClassC should handle and implement the events, handling them and letting them "bubble up" (invoking their own, same, event) for ClassD to handle correctly.
Basically, all of them should handle all events, either reacting to them (as in ClassB to ClassA's events) or just propagating them.
Find nice solution here:
Csharp-NotificationCenter
Related
I do not know if there is an answer to this - I can not seem to find examples so maybe my terminology is not right or maybe this should not be done so forgive me for asking.
I have a base class with an object that has several events and event handling code - basically this is a boiler plate process using a FileSystemWatcher.
In my base I have all the code wired up for handling particular events and error handling.
The issue is that I am looking to be able to control what events of file system watcher the base class should subscribe to (was thinking to include all and use a switch case to add them) but then I need to handle them in the derived class and not in the base - because there is specific functionality of the derived classes that I want. I do not want to implement all the events in the base if possible - because I do not want the overhead when 4 to 8 of these derived classes are running. One thing I would like is force a derived class to SUBSCRIBE to an event.
I know from DCcoder that abstract was key in forcing methods to be 'must inherit' but I am at a loss on forcing the subscription.
public abstract class myBase
{
public event EventHandler<string> MessageAvailable;
protected void OnMessageAvailable(string e)
{
MessageAvailable?.Invoke(this, e);
}
public event EventHandler<Exception> Error;
protected virtual void OnError(Exception e)
{
Error?.Invoke(this, e);
}
}
public myderivedclass : myBase
{
this.Message += IfYouwantTo;
this.Error += REQUIRE_THIS_SUBSCRIPTION_HandleErrorHere;
}
DerivedClass needs to actually handle the events so do I create an empty event handler in the base class and use an interface to force my derived class to override the base or rather than that force the derived class to implement the handler ??
Or am I going about this all wrong ?
Any examples are appreciated ..
I have recently started working with C# events and I am really liking the ease of use they offer (I come from a java background where we have to do all this event stuff manually).
However, there is one thing from my java background that I am missing: the inheritance side.
In java, if you want to subscribe to an event, you would inherit an interface such as IKeyListener. The interface would contain all of the method event signatures which you would then implement in the subscribing class. Whenever a key would be pressed, these implemented methods would be fired. Much the same as C#. However, unlike in java, I am unable to identify which classes subscribe to certain events because they don't actually inherit anything.
So if I wanted a list of objects which have key press event support I could do
List<IKeyListener> keyListeners = new ArrayList<IKeyListener>();
However, I don't see any good way to do this in C#. How would I be able to create list similar to the one above? Preferably without much "hackiness".
Thank you.
In C# you can define the event in an interface like this:
public interface IDrawingObject
{
event EventHandler ShapeChanged;
}
Then you can do what you want and store them like this:
var shapes = new List<IDrawingObject>();
A class can then implement the interface like this:
public class Shape : IDrawingObject
{
public event EventHandler ShapeChanged;
void ChangeShape()
{
// Do something here before the event…
OnShapeChanged(new MyEventArgs(/*arguments*/));
// or do something here after the event.
}
protected virtual void OnShapeChanged(MyEventArgs e)
{
if(ShapeChanged != null)
{
ShapeChanged(this, e);
}
}
}
So in other words the event becomes part of the interface and if a class implements that interface, the class must provide an implementation for the event as well. That way you are safe to assume the implementing class has the event.
Finally every event will need to share some info about the event. That class can inherit the EventArgs class like below:
public class MyEventArgs : EventArgs
{
// class members
}
I have a Generic class which is inherited from ObservableCollection.
I want to get the notifications in this class whenever some particular properties of my object in this collection changes, not add or remove object but edit/update object.
I have some carrier classes which will be passed as Type argument to this generic class. Upon changing property in these classes, I want to raise an event which will further be handled in this Generic class.
public class CustomCollectionGenericClass<T>:ObservableCollection
{
}
public class HelperClass
{
public string Name
{
get{return _name;}
set{_name=value;
//raise some event which will be handled in custom collection class
}
}
}
I have no idea how to subscribe and raise event in this case
You can only subscribe to non-static events against instances of a class. You cannot subscribe to non-static events from a type.
In your case, what you could do is add a type constraint, making sure that the constraint enforces that event to be available on that class and then subscribe to the events of an instance:
public class GenClass<T> where T : RoutineClass
{
public someMethod(T yourInstance)
{
yourInstance.EventToSubscribe += yourHandler;
}
}
In this example, I have added a method which receives an instance, since you did not have an instance anywhere inside your generic class. This might not be what you need, but either way, you need an instance to be able to subscribe to events.
Some clarification: this applies when you have non-static events (as per your code). In case you have static events, you can subscribe to events against the type.
I have two same events in different classes:
A.eventA
B.eventB
These two events: eventA and eventB are defined via the same delegate therefore the events have the same return value and parameters. Is it possible to fire A.eventA in the moment when B.eventB is fired?
I can write a method:
void return-value-of-delegate connect(parameters of delegate)
{
if (A.eventA != null)
{
A.eventA(parameters of delegate);
}
}
I was just wondering if I can shorten my code.
Thanks!
(Note: My code is a WPF project therefore WPF tag.)
EDIT: In class A is reference to the class B.
Whenever EventB fires, EventA also fires:
class A {
private B b;
public event EventHandler EventA {
add {
b.EventB += value;
}
remove {
b.EventB -= value;
}
}
public A() {
b = new B();
}
// ...
}
All the event listeners are registered in class B now.
You can not raise an event outside of the class. Only the class itself can raise it's own events. You can on the other hand, expose a public method accepting same parameters which internally raises the specified event.
Using Reflection is also not an option which only allows you to subscribe to and remove a subscription from an event of another class.
No, you can't, unless the code is in the class that declares the event. Events can only be fired from the declaring class. You probably have to consume an event with the arguments from both classes and in return fire the event, but you can't guarentee they will be fired at the same time, only about the same time, depending on the methods registered to each event, as they will be executed in the same thread.
The fact that the events are defined in different classes means that they are not the same event, even though they may have the same signature. You can't fire events from two separate classes at once.
Amongst other things, consider that an event is typically fired from an instance of a class. Which instance of B.eventB would you fire when A.eventA occurs?
I'm a bit confused about C# Classes and their deconstructor.
I have to consume a few event handlers in a class instance I'm getting in the constructor:
public Foo(IFooHandler handler)
{
handler.Load += Load;
handler.Close += Close;
}
I need to unsubscribe to that event when the Foo class is destroyed. Do I implement IDisposable and unsubscribe in there, or in a deconstructor? I need to consume those events, I can't do it another way.
For one of the classes, I create an instance, check progress, and then the class instance goes out of scope. For another it stays in the MainForm until the form is closed. The first is what I'm worried about because it may still have a reference to that event handler and not properly go.
I don't want to leak memory. When and how should I unsubscribe?
Don't do it in the destructor, because it won't be called while the event handlers are attached : when you attach an instance method of Foo as a handler for an event of Bar, Bar will hold a reference to Foo, so Foo won't be garbage collected, and its destructor won't be called.
You should implement IDisposable, and dispose your object explicitly
public void Dispose()
{
if (handler != null)
{
handler.Load -= Load;
handler.Close -= Close;
}
}
If you ever face the problem of having class A be a long lived class and class(es) B be short lived ones that subscribe to events of class A then you probably would be interested in the Weak Event Pattern. It can be a problem that you do not discover is one until it is to late i.e. Princeton self driving car.