Re: Events by Peter
Peter
Thu Aug 28 09:43:45 CDT 2008
On Thu, 28 Aug 2008 06:06:18 -0700, Ferdinand Zaubzer
<ferdinand.zaubzer@schendl.at> wrote:
> Hi,
> I have a tricky problem with events. I have two objects of the same
> type: O1 and O2.
> I want to pass the event handlers of O1 (the events of O1 are already
> connected to appropriate event handlers) to O2.
>
> Is there any possibility to achieve this?
If you have control over the code implementing the events in the type,
yes. You could expose the event's field through a property or provide a
method that you can pass one instance in in order to copy the event's
field from one to the other.
For example:
class A
{
public event EventHandler MyEvent;
private EventHandler MyEventSubscribers
{
get { return MyEvent; }
}
// Simply add the exposed delegate from O1 to the current
// instance's event delegate field.
private void SomeMethod(A O1)
{
MyEvent += O1.MyEventSubscribers;
}
}
or (probably better, since it makes the subscription go through the
event's add method)
class A
{
public event EventHandler MyEvent;
// Explicitly subscribe the current instance's event
// delegate field to the passed-in instance's event.
private void AddMyEventSubscribers(A O2)
{
a.MyEvent += MyEvent;
}
}
If you don't have control over the code but the events are in a sub-class
of the actual type, the best you can do is have O1 subscribe to O2's
events and forward to its own subscribers (assuming you have control over
raising the events within the same class...such as in Control with the
OnXXX and Raise/PerformXXX methods).
For example:
class A
{
public event EventHandler MyEvent;
protected void RaiseMyEvent(EventArgs e)
{
EventHandler handler = MyEvent;
if (handler != null)
{
handler(this, e);
}
}
}
class B : A
{
private void MyEventHandler(object sender, EventArgs e)
{
RaiseMyEvent(e);
}
// Subscribe to O2's event, so that when it's raised the
// current instance can raise its own event, effectively
// hooking all of this object's handlers to O2's event.
public void AddMyEventSubscribers(A O2)
{
O2.MyEvent += MyEventHandler;
}
}
Note that there's a subtle difference between these first two approaches.
In the first case, the code is literally copying the current state of the
events from one instance to another. Later changes to one instance's
subscribers won't affect the other. In the second case, one instance is
essentially in charge of the actual subscribers and is forwarding from
another instance. Changes to the first instance's event subscriptions
will also affect who gets notified if the second instance's event is
raised.
For flexibility one might think the second approach is better, and it
could be. But beware of circular event subscriptions. :) It subscribes
O1 to O2's event and if you wind up with O2 somehow subscribed to O1's
event, you'll wind up in an endless loop (well, until the stack overflows,
anyway).
Finally, if you have no control over the class at all, then your best bet
is probably to create a "middle-man" or "mediator" class that exposes the
same events. The actual subscribers would subscribe to those events in
that class, and then that class would subscribe to each instance of the
type that actually implements the events, forwarding the events as
necessary.
For example:
class A
{
public event EventHandler MyEvent;
}
class Mediator
{
// Instead of subscribing to the event on O1, client classes
// would instead subscribe to this event
public event EventHandler MyEvent;
// This would be done once for each of O1 and O2
public void Subscribe(A a)
{
a.MyEvent += MyEventHandler;
}
private void MyEventHandler(object sender, EventArgs e)
{
RaiseMyEvent(e);
}
private void RaiseMyEvent(EventArgs e)
{
EventHandler handler = MyEvent;
if (handler != null)
{
handler(this, e);
}
}
}
Depending on the exact situation, it might make sense for the Mediator
class to be static (e.g. if you know for sure you're always going to have
just one mapping).
Hope that helps.
Pete