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.
Related
I'm studying some examples provided by Microsoft for win8 development. I opened BasicControls sample and noticed LayoutAwarePage class and more precisely ObservableDictionary class. Reading about implementing events and raising them I can't see who's responsible to raise MapChangedEventHandler event. Based on parameters I believe that private void InvokeMapChanged(CollectionChange change, K key) method do this. But according to MSDN we need to provide a protected method that begins with On which doesn't occur in ObservableDictionary.
So, who raises MapChangedEventHandler?
An event in a class can be raised from within the class without need of an additional method to that.
So, if MapChangedEventHandler is an event, it can be called from inside the class just by this:
if (MapChangedEventHandler != null)
MapChangedEventHandler( parameters );
The only motive I can see (I'm not an expert) to the existance of those OnWhatever methods is to allow raising events from outside the class, or from some derived class, since events can only be raised from inside the declaring class.
Those OnWhatever methods must be some good practice (not a rule, nor a compiler rule).
Maybe they also take care of some additional stuff together with raising the event.
If they are not provided, probably they are not meant to be called from outside or from a derived class.
By the way, the MapChangedEventHandler is not an event. It's a delegate.
Events can be of that type, but their names are independant.
Like this:
class TestClass
{
these are the events of the class:
public event MapChangedEventHandler SomeEvent1;
public event MapChangedEventHandler SomeEvent2;
public event MapChangedEventHandler SomeEvent3;
//now this method calls the events (events can only be raised from inside the class)
public void SomeMethod()
{
//do lots of stuff
if (SomeEvent1 != null) SomeEvent1(whatever arguments it takes);
//do other stuff
if (SomeEvent2 != null) SomeEvent2(another arguments);
}
//now, if you want to let derived classes to raise events...
protected void OnSomeEvent3(Same Parameters As MapChangedEventHandler)
{
if (SomeEvent3 != null) SomeEvent3(parameters);
}
}
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
I have a need to implement a complex aspect which needs to be able to introduce an interface, as well as several pointcuts. I'm not sure how to do this.
My goal is to intercept some field setters on a class, so that I can introduce some behaviour (via event handlers on the decorated fields). I want to transform some data, and then raise an event which is declared on a specific interface, so I want to introduce this interface to the class which contains these fields.
The simplest concept would be a container which captures all events on its children and transforms them into a single external event on the container class.
So, I know how to introduce method pointcuts using LocationInterceptionAspect;
public override void OnSetValue(LocationInterceptionArgs args)
{
// attach event handler to args.Value.SomeEvent,
}
And also how to introduce interfaces/methods with an InstanceLevelAspect.
But not how to combine the 2 into a single aspect.
I can't simply introduce an interface or member inside a LocationInterceptionAspect, as the scope is the location, not the containing type, and it won't compile.
I could always separate this into 2 aspects, however this means each aspect will not function independently, and I'd have to ensure both are always applied together.
It appears that I can add an OnLocationSetValueAdvice (via attributes) to an InstanceLevelAspect, and this works.
[IntroduceInterface(typeof(IMyInterface)]
public class CustomAspect : InstanceLevelAspect
{
[OnLocationSetValueAdvice]
[MulticastPointcut(Targets = MulticastTargets.Field, Attributes = MulticastAttributes.Instance)]
public void OnSetValue(LocationInterceptionArgs args)
{
...
}
}
I know the class implementing an interface must implement all its method. But what does event inside the interface mean?
It means that the type must implement the event - so that clients can subscribe to those events.
Think of events as pairs of methods (add/remove) just as properties have get/set. Just as you can have properties in interfaces, you can have events: the implementation has to provide the appropriate add/remove methods and the metadata to tie them to the event. In C# this can be done using field-like events:
public event EventHandler EventFromInterface;
or with explicit add/remove methods:
public event EventHandler EventFromInterface
{
add { ... }
remove { ... }
}
It means anything implementing that interface must raise that event. Pretty much the same as a Method or Property within an interface.
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?