Say I have an event defined in an interface.
I then have many classes that implement that interface.
The creation of these classes is managed by StructureMap.
Now say I have one delegate that I want to use as the event handler for ALL of these newly created instances.
Is there a way to tell StructureMap to append an event handler to objects it creates?
(NOTE: My current solution is to create a Notifier class and pass that in through the constructor, which gets the job done, but I'm curious if I can eliminate the middleman.)
If you take a look at http://structuremap.sourceforge.net/Interception.htm there is an explanation to EnrichWith()
Add the the event handler and return the original object and you should have what you want.
Related
I am writing a wrapper around a class that extends some parts of a 3th party class. It adds some functionality that was missing. And by keeping it a class I can use it in multiple projects.
However I wonder how should I wrap around something that raises an event.
So that I can extend those events as well but still be able to raise an event for apps that use my extended class. So it acts a bit like a passtrough with added functionality. Let me clarify this with a bit of code
So MyExtend class has this code fragment in its constructor
thirdpartyClass theirclass += new thirdpartyclass()
thirdpartyClass.init()
theirclass.EventX = += MyWrapper_Method
Then the wrapper for the event inside MyExtend class look like
Public Void MyWrappedEvent_method()
{
messagebox("logged it") //it actually logs to a database but i keep it short here
}
Now some other program in the future should be able to use MyExtend class.
And be able to do other things besides logging it, when a certain events (ea MyWrappedEvent) happens so that i could write
Using MyExtend;
//somwhere in main
MyExtend HasExtended = new MyExtend();
HasExtended.MyWrapper += NewFutureRoutine()
//...
// ..
public void NewFutureRoutine()
{
//when i call this event i wont need to care about logging thats allready in it
// so i could focus on other tasks ea:
Arduino.Controller(setHardwarePin,high);
}
In order to let your MyExtend class handle the events, you will need to catch the desired event in your class, then fire another event and subscribe to it.
I would recommend to read and follow the following links/instructions:
Raising an Event
How to: Raise and Consume Events
How to manually invoke an event?
this is more theoretical question. I know that every event in C# has to have 2 parameters: object and eventargs. It's clear. But why does the basic eventargs class even exist when it's impossible to pass any data with it? Of course I can make new EventArgs class that inherits from the basic one, but I just miss the point of the class that can't carry any data.
This is about future-proofing your code.
The theory goes that if at some point you discover that your code should publish more data to event handlers than it did before, you can easily just add more properties to the object you pass to those event handlers.
If, for some reason, the class that holds those data is not under your control you inherit from it, and add your properties to the inherited class. So far so good.
But, if you never passed any object to the event handler in the first place, you cannot add a new parameter to the event delegate without existing code breaking.
As such, that you pass what amounts to a dummy object, EventArgs.Empty to events now give you the ability to later on inherit from EventArgs and start passing data to the same events, without having to change the event handlers at all. I most cases, you don't even have to recompile assemblies that uses the event handler.
So EventArgs is just a handy class you pass to event handlers, you could just as easily create your own, but since it has no meaning except to be a placeholder for possible future changes, there's no need to create your own, simply use EventArgs.
Consider we have a class with event declared:
public class FooBar
{
public event EventHandler FooBarEvent;
}
Despite of "publicness" of the event, we cannot call FooBarEvent.Invoke from outside.
This is overcame by modyfing a class with the following approach:
public class FooBar
{
public event EventHandler FooBarEvent;
public void RaiseFooBarEvent(object sender, EventArgs eventArguments)
{
FooBarEvent.Invoke(sender, eventArguments);
}
}
Why accessing public events outside is limited by adding and removing listeners only?
Defining a public event merely gives consumers the ability to subscribe and unsubscribe from it. The ability to raise the event is limited to the type hierarchy which declares the event.
Allowing all subscribers to also be able to raise the event would be a bit chaotic. Imagine for example I had a TextBox class which had a Focused event. If any old consumer could raise the event then the Focused event could easily fire when the TextBox class wasn't actually focused. This would make it nearly impossible to maintain any type of invariant during an event.
Personally I think this is done to properly convey the design principles behind the whole events architecture.
The purpose of an event is to notify a listener of said event occurring in a given object.
What's the point of raising events of classes that don't belong to you?
That's what events are for. If you want to invoke it publicly you probably need delegates not events
Events gives encapsulation,
It prevents other classes from assigning anything to it
It prevents passing it as a parameter to methods
It prevents assigning it to any variable
It prevents calling it from another classes (not even derived classes have access to it)
etc
public accessibility tells that it can be subscribed from anywhere, not invoked from anywhere.
the answer to your question is
An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object.
Invoking the event from outside doesn't makes sense therefore it is not allowed.
I think you should change your perspective on how events work. Other classes shouldn't "own" the event and trigger it. Classes which "listen" to the event by "subscribing" to it and do a certain action when this event occurs.
That's the way the language is defined - an event can only be fired by the owning class. If you must fire it from a different class, have the owning class define a public method that will fire the event:
public FireFooBarEvent (object sender, EventArgs args)
{
if(FooBarEvent != null)
FooBarEvent(sender, args);
}
And call this method from any class.
I am trying to understanding the Event Aggregator pattern from an architecture and design view point. I have never used Prism in WPF before, but I'm studying how it works on MSDN.
It seems to me that for every event, the user has to create a new event object that extends the CompositePresentationEvent. It also appears that the new event object has no functionality other than those it inherited from (it usually has no code for itself).
So for example:
A AddNewStuffEvent would look like:
public class AddNewStuffEvent : CompositePresentationEvent<Object> {} //The end of the class
For a HealthChangeEvent:
public class HealthChangeEvent: CompositePresentationEvent<Object> {} //The end of the class
For a BookFlipEvent:
public class BookFlipEvent: CompositePresentationEvent<Object> {} //The end of the class
For a BookCloseEvent:
public class BookCloseEvent: CompositePresentationEvent<Object> {} //The end of the class
And this can go on forever for every little small event for BookOpenEvent, BookTearEvent, etc. So, in a particular namespace folder, there will be a whole ton of event classes, and the Event Aggregator is going to be loaded with all these event objects during runtime. That's, every little small event needs an empty class? Is this how it works? What could be a better way for this?
Yes, every event type needs its own class, which you have to define.
It also appears that the new event object has no functionality other than those it inherited from
The purpose is simply to provide strong typing for the event. This makes it easier to write code to subscribe to them. Ie, the subscribing code can be written like:
aggregator.GetEvent<AddNewStuffEvent>().Subscribe(Handler);
This is a preferable approach to alternatives, such as reliance on "magic strings" in the form of say aggregator.GetEvent("AddNewStuffEvent").Subscribe(Handler) (which could not be verified at compile time.
Is it possible to register multiple event listeners?
We currently register event listeners using .ExposeConfiguration(AddSoftDelete) in which AddSoftDelete is a class registering the listener;
private static void AddSoftDelete(Configuration config)
{
config.SetListener(ListenerType.Delete, new SoftDeleteListener());
}
We have found that we cannot register multiple event listeners of the same type, i.e. we cannot register more than one listener for "ListenerType.Delete".
Is it possible to register new listeners without overriding any existing ones?
Solved...
Have managed to register multiple listeners using the following code;
config.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[]
{
new Listener1(),
new Listener2()
};
Repeat for each ListenerType.
The listeners are not actually listeners, they are implementors. There could only be one implementation of an "event".
You could implement a listener where you could plug in several implementations. For instance an implementation for different entity types. You could pass the "event" to each implementation until one of them handles it (eg. when the ISoftDeletable interface is implemented, the SoftDeleteImplementor is handling it). You need to care about competing implementors (more the one could be handling it, the order matters in which you call them).
Why is there a need to register more than one ListenerType.Delete?
If you've got multiple event listeners on one type, there will be some performance issues on your application. If you want to handle different entities with this listener, so do it in your SoftDeleteListener class.
I do something similar in my code. There should be an AppendListeners(ListenerType type, object[] listeners) method on the NHibernate.Cfg.Configuration object.
There's also a SetListeners method which I assume replaces the listener list instead of adding on to it.