WeakEventManager with event name lambda expression and custom event accessors

1.3k views Asked by At

I have been looking in to subscribing to an event using a weak event pattern. With the .NET 4.5 framework, we have a slick looking WeakEventManager class. Weakly subscribing to an event is as simple as

WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source, "SomeEvent", source_SomeEvent);

I'm not a big fan of 'stringly-typed' code however. I have been trying to find a way around using the string name of the event to subscribe to. The only way I have found to obtain the name of the event is using a lambda expression in the class that defines the event. In my scenario, I own the class defining the event so I can change it however I like. I have been trying to find a clean way to subscribe and unsubscribe to my event and here is what I disliked the least.

public event EventHandler<EventArgs> LoggingOn;
public event EventHandler<EventArgs> LoggingOn_Weak
{
    add
    {
        var eventName = this.GetEventName(() => this.LoggingOn);
        WeakEventManager<CurrentUser, EventArgs>.AddHandler(this, eventName, value);
    }

    remove
    {
        var eventName = this.GetEventName(() => this.LoggingOn);
        WeakEventManager<CurrentUser, EventArgs>.RemoveHandler(this, eventName, value);
    }
}

// In a base class view model in my scenario
private string GetEventName<T>(System.Linq.Expressions.Expression<Func<T>> expression)
{
    return (expression.Body as System.Linq.Expressions.MemberExpression).Member.Name;
}

protected void OnLoggingOn(object sender, EventArgs e)
{
    var handler = this.LoggingOn;
    if (handler != null)
    {
        handler(sender, e);
    }
}

Using custom event accessors I was able to avoid clunky (in my opinion) methods like LoggingOn_Subscribe(EventHandler) or adding name properties for each event. Unfortunately it is not so intuitive in that people subscribing to the event are doing so in the classic manner but have no idea other than the "_Weak" part of the name that indicates it is being subscribed to weakly.

As for my questions..

1) I have never used weak events or custom event accessors before. The code above appears to work, however, I would just like to make sure there is nothing technically wrong with it. Is there anything I'm doing here to shoot myself in the foot?

2) From a design perspective, is this a terrible idea? Are there any major design concerns I should consider? Is there better alternative? Should i just suck it up and subscribe from my subscriber using a stringly-typed event name?

Thoughts?

2

There are 2 answers

0
garyhsu On BEST ANSWER

With .NET 4.6 you can now use the nameof() expression:

WeakEventManager<IMyGrid, MyEventArgs>.AddHandler(myGrid, nameof(IMyGrid.MouseDown), OnMouseDown);
0
Tergiver On

What you could do is use the built-in System.ComponentModel.EventHandlerList. This class is a container for all of your object's event handler delegates. The primary benefit is that no storage is allocated on your object for each event unless there is actually someone subscribed to an event.

The secondary benefit is that in order to use it, you must provide a key for your event.

class MyObject
{
    protected EventHandlerList Events = new EventHandlerList();

    public static Event1Key = new object();
    public event Event1
    {
        add { Events.AddHandler(Event1Key, value); }
        remove { Events.RemoveHandler(Event1Key, value); }
    }
}

Now you could create a variation of WeakEventManager that accepted keys rather than string names. So the consumer could say

WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source, EventSource.Event1Key, source_SomeEvent);