You need what's called a "weak reference delegate". That is, you want
your Datasource to hold a _weak reference_ to your Customer, not a
regular reference. Weak references don't count when the garbage
collector is deciding whether an object is still referenced and
therefore shouldn't be collected.
Here is my code for a wrapper that allows callers to "weak subscribe"
to a static event. Sorry about the length: the code includes lots of
comments.
#region WeakEventReference
/// <summary>
/// Used to subscribe to <em>static</em> events
/// when the subscriber wants to subscribe via a weak reference rather
than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event subscribers
to be
/// garbage collected without having to unsubscribe to the event, but
it also
/// comes with a host of concurrency considerations, not the least of
which
/// is that the event handler method on the subscriber could be called
and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public abstract class WeakEventReference : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller's responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments that
/// <paramref name="subscriberMethod"/> should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="provider"/> should be expecting as a subscriber.
/// </param>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="provider"/> does not allow event handlers
/// of type <paramref name="eventHandlerType"/> to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this.GetType().GetMethod("ItemAdded"),
///
typeof(EventProviderType).GetEvent("StaticEvent")).Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider, Type eventArgumentType, Type
eventHandlerType) : base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if
(!subscriberMethod.DeclaringType.IsAssignableFrom(subscriber.GetType()))
{
throw new ArgumentException(String.Format("Cannot subscribe an
object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(),
subscriberMethod.DeclaringType), "subscriber");
}
this._subscriberMethod = subscriberMethod;
ParameterInfo[] subscriberMethodParameters =
subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method subscribing
to the event takes {0} parameters, not the required two parameters
(object, {1}).", subscriberMethodParameters.Length, eventArgumentType),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type System.Object.", subscriberMethodParameters[0]),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
this._provider = provider;
if (!this._provider.EventHandlerType.Equals(eventHandlerType))
{
throw new ArgumentException(String.Format("EventInfo is for a {0}
event handler, not a {1}", this._provider.EventHandlerType,
eventHandlerType), "provider");
}
}
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This is
passed explicitly
/// so to search for the <paramref name="subscriberMethod"/> at the
correct
/// level of the class hierarchy, since <paramref name="subscriber"/>
may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller's responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments that
/// <paramref name="subscriberMethod"/> should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="providerEvent"/> should be expecting as a
subscriber.
/// </param>
/// <exception cref="MissingMethodException">
/// <paramref name="subscriberType"/> does not declare a method
/// called <paramref name="subscriberMethod"/>.</exception>
/// <exception cref="MissingMemberException">
/// <paramref name="providerType"/> does not declare a static event
/// called <paramref name="providerEvent"/>.</exception>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="providerEvent"/> does not allow event handlers
/// of type <paramref name="eventHandlerType"/> to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this, "ItemAdded",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, Type subscriberType,
string subscriberMethod, Type providerType, string providerEvent, Type
eventArgumentType, Type eventHandlerType) : base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberType == null)
{
throw new ArgumentNullException("subscriberType");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if (!subscriberType.IsAssignableFrom(subscriber.GetType()))
{
throw new ArgumentException(String.Format("Cannot subscribe an
object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(), subscriberType),
"subscriber");
}
this._subscriberMethod = subscriberType.GetMethod(subscriberMethod,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (this._subscriberMethod == null)
{
throw new MissingMethodException(String.Format("Subscriber of type
'{0}' does not have an event handler method called '{1}'.",
subscriber.GetType(), subscriberMethod));
}
ParameterInfo[] subscriberMethodParameters =
this._subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method subscribing
to the event takes {0} parameters, not the required two parameters
(object, {1}).", subscriberMethodParameters.Length, eventArgumentType),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type System.Object.", subscriberMethodParameters[0]),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
if (providerType == null)
{
this._provider = null;
}
else
{
if (providerEvent == null)
{
throw new ArgumentNullException("providerEvent");
}
this._provider = providerType.GetEvent(providerEvent);
if (this._provider == null)
{
throw new MissingMemberException(String.Format("Provider type
'{0}' does not publish a static event called '{1}'", providerType,
providerEvent));
}
if (!this._provider.EventHandlerType.Equals(eventHandlerType))
{
throw new ArgumentException(String.Format("Event provider event is
for a {0}, not a {1}", this._provider.EventHandlerType,
eventHandlerType), "providerEvent");
}
}
}
/// <summary>
/// Gets the event provider for the event to which the weak
/// reference delegate has subscribed.
/// </summary>
/// <value>Information about the event to which this weak
/// reference is subscribing.</value>
protected EventInfo Provider
{
get { return this._provider; }
}
/// <summary>
/// Gets the method information for the method to call on the
/// event subscriber.
/// </summary>
/// <value>Information about the method that this weak reference
/// is to call each time the event occurs.</value>
protected MethodInfo SubscriberMethod
{
get { return this._subscriberMethod; }
}
}
#endregion
#region SystemEventWeakReference
/// <summary>
/// Used to subscribe to static events that require <see
cref="System.EventHandler"/>,
/// when the subscriber wants to subscribe via a weak reference rather
than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event subscribers
to be
/// garbage collected without having to unsubscribe to the event, but
it also
/// comes with a host of concurrency considerations, not the least of
which
/// is that the event handler method on the subscriber could be called
and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public class SystemEventWeakReference : WeakEventReference
{
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller's responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler"),
///
typeof(EventProviderType).GetEvent("StaticEvent")).Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) :
base(subscriber, subscriberMethod, provider,
typeof(System.EventArgs), typeof(System.EventHandler))
{ }
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This is
passed explicitly
/// so to search for the <paramref name="subscriberMethod"/> at the
correct
/// level of the class hierarchy, since <paramref name="subscriber"/>
may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller's responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, this, "MyEventHandler",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent) :
base(subscriber, subscriberType, subscriberMethod, providerType,
providerEvent, typeof(System.EventArgs), typeof(System.EventHandler))
{ }
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler")).Delegate;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers a
simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod) : this(subscriber, subscriberMethod, null)
{ }
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This is
passed explicitly
/// so to search for the <paramref name="subscriberMethod"/> at the
correct
/// level of the class hierarchy, since <paramref name="subscriber"/>
may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, "MyEventHandler")).Delegate;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers a
simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod) : this(subscriber,
subscriberType, subscriberMethod, null, null)
{ }
/// <summary>
/// The event handler that will really be subscribed to the event.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="e">Arguments giving more information about the
event.</param>
public void Handler(object sender, System.EventArgs e)
{
object sub = this.Target;
if (sub != null)
{
this.SubscriberMethod.Invoke(sub, new object[] { sender, e });
}
else if (this.Provider != null)
{
this.Provider.RemoveEventHandler(null, this.Delegate);
}
}
/// <summary>
/// The delegate to add to the event dispatch chain.
/// </summary>
/// <value>The event handler delegate for this object's
/// <see cref="Handler"/> method.</value>
public System.EventHandler Delegate
{
get { return new System.EventHandler(this.Handler); }
}
}
#endregion