I have three objects ObjectA has an ObjectB, ObjectB has an ObjectC. When ObjectC fires an event I need ObjectA to know about it, so this is what I\'ve done...
As other answers have stated, this is they way to do it.
But you can go beyond!!! I've just implemented a good data structure on it, and it's like to give you a spin on it.
Would be nice to have an automatic event bubbling? You could implement it using Reflection. My way is to define an Interface/Base class which declares an event (or a set of events). Then, the parameterless constructor of a base class will iterate other its properties/fields, and register automatically the members events for event propagation.
There are some restriction on design, but if you have a deep structure and/or many (structured) events, it could be nice to have everything setup without any additional line of code.
An initial base class could be:
class BaseObject {
public BaseObject() {
FieldInfo[] fInfos = this.GetType().GetFields(...);
foreach (FieldInfo fInfo in fInfos) {
object fInfoValue = fInfo.GetValue(this, null);
if (fInfoValue is BaseObject) {
BaseObject bMemberObject = (BaseObject)fInfoValue;
bMemberObject.MyEvent += new EventHandler(delegate() {
if (this.MyEvent != null)
MyEvent();
});
}
}
public event MyEvent = null;
}
Of course, as already suggested, follow the event delegate delegate(object sender, EventArgs args) (I've used a simpler event for clarity). Naturally, is implicit that you classes A, B and C derives directly from BaseObject.
Note that any logic could be implemented to bind structured events (you could be the nested event registration using the name and/or other reflected properties.
Another approach, is to wrap it using add/remove:
public class ObjectB
{
ObjectC objC;
public ObjectB()
{
objC = new ObjectC();
}
public event EventFiredEventHandler EventFired
{
add { this.objC.EventFired += value; }
remove { this.objC.EventFired -= value; }
}
}
That's the way I do it. however I would recommend change your firing mechanism to this to make it thread safe
protected void OnEventFired()
{
var tmpEvent = EventFired;
if(tmpEvent != null)
{
tmpEvent();
}
}
This keeps it from failing if EventFired becomes null between the null check and the firing.
Also it is somewhat of a standard to follow the EventHandler pattern for your event delegates.
protected virtual void OnEventFired(EventArgs e)
{
var tmpEvent = EventFired;
if(tmpEvent != null)
{
tmpEvent(this, EventArgs.e);
}
}
I was wrong about the threadsafe pattern, here is the full threadsafe event pattern
/// <summary>
/// Delegate backing the SomeEvent event.
/// </summary>
SomeEventHandler someEvent;
/// <summary>
/// Lock for SomeEvent delegate access.
/// </summary>
readonly object someEventLock = new object();
/// <summary>
/// Description for the event
/// </summary>
public event SomeEventHandler SomeEvent
{
add
{
lock (someEventLock)
{
someEvent += value;
}
}
remove
{
lock (someEventLock)
{
someEvent -= value;
}
}
}
/// <summary>
/// Raises the SomeEvent event
/// </summary>
protected virtual OnSomeEvent(EventArgs e)
{
SomeEventHandler handler;
lock (someEventLock)
{
handler = someEvent;
}
if (handler != null)
{
handler (this, e);
}
}