Ramin Bateni
Ramin Bateni

Reputation: 17415

Unsubscribe from original event when try unsubscribe from a variable of that EventHandler

I'm trying to unsubscribe attached method to my event. I have this code:

public event EventHandler MenuItemSelectionChanged;

var eh = MenuItemSelectionChanged;
eh -= TheMethod;

After run the above code result is:

MenuItemSelectionChanged: Is Not Null

el: Is Null

But I want to unsubscribe TheMethod from MenuItemSelectionChanged, by using eh (a pointer to the EventHandler). How can I use eh to remove TheMethod from eh and MenuItemSelectionChanged

I need this result:

MenuItemSelectionChanged: Is Null

el: Is Null

My main scenario is:

Inside TargetClass.cs:

    public event EventHandler MenuItemSelectionChanged;

    public void UnsubscribeFromEvent(ThisClassEventHandlerNames eventHandlerName, Dictionary<FrameworkElement, MethodInfo> eventHandlerInfos)
    {
        var eh = GetEventHandler(eventHandlerName);
        if (eh == null) return;

        foreach (var eventHandlerInfo in eventHandlerInfos)
        {
            var info = eventHandlerInfo;

            if (eh == null)
                break;
            
                var invocationList = eh.GetInvocationList().Where(x =>
                    Equals(x.Target, info.Key) &&
                    x.Method == info.Value);

            foreach (var myDeligate in invocationList)
            {
                if (eh == null)
                    break;

                // I HAVE A PROBLEM HERE>>
                eh -= (EventHandler) myDeligate;
                // RESULT: eh is null BUT MenuItemSelectionChanged is not null
            }
        }
    }

    public enum ThisClassEventHandlerNames
    {
        MenuItemSelectionChanged
    }

    private EventHandler GetEventHandler(ThisClassEventHandlerNames eventHandlerName)
    {
        EventHandler result = null;
        switch (eventHandlerName)
        {
            case ThisClassEventHandlerNames.MenuItemSelectionChanged:
            {
                result = MenuItemSelectionChanged;
                break;
            }
            default:
            {
                result = null;
                break;
            }
        }
        return result;
    }

I call the above code in my wpf user control with some codes like this:

Inside MyUserControl.cs:

TargetClassObject.UnsubscribeFromEvent(
    TargetClass.ThisClassEventHandlerNames.MenuItemSelectionChanged,
    new Dictionary<FrameworkElement, MethodInfo>
    {
        {
            this,
            Infrastructure.Utility.GetMethodInfo<MyUserControl>(x => x.MenuControl_MenuItemSelectionChanged(null, null))
        }
    });

Really I want to unsubscribe a method from an event by call a method inside that class (targetClass) by this parameters:

A) An enum value (to get event by it)

B) A method info (to unsubscribe its method from the event)

Note: My platform is C#, WPF, .NET Framework 4.5

Upvotes: 2

Views: 94

Answers (1)

IS4
IS4

Reputation: 13187

When you move MenuItemSelectionChanged to a variable and then assigning to that variable, you aren't really changing the original delegate's invocation list. eh -= TheMethod; is just the same as eh = eh - TheMethod; (if you are inside the class), but this produces a new MulticastDelegate and doesn't modify the original one.

So to answer your first code:

public event EventHandler MenuItemSelectionChanged;

var eh = MenuItemSelectionChanged;
eh -= TheMethod;
MenuItemSelectionChanged = eh;

However, you want to change the event dynamically, so either you can add a second method that gets ThisClassEventHandlerNames and EventHandler and assigns it back. Or you can modify the GetEventHandler method to return a reference to the handler:

private delegate void HandlerModifier(ref EventHandler handler);
private bool ModifyEventHandler(ThisClassEventHandlerNames eventHandlerName, HandlerModifier mod)
{
    switch (eventHandlerName)
    {
        case ThisClassEventHandlerNames.MenuItemSelectionChanged:
        {
            mod(ref MenuItemSelectionChanged);
            return true;
        }
        default:
        {
            return false;
        }
    }
}

public void UnsubscribeFromEvent(ThisClassEventHandlerNames eventHandlerName, Dictionary<FrameworkElement, MethodInfo> eventHandlerInfos)
{
    ModifyEventHandler(
        eventHandlerName,
        delegate(ref EventHandler eh)
        {
            if (eh == null) return;

            foreach (var eventHandlerInfo in eventHandlerInfos)
            {
                var info = eventHandlerInfo;

                if (eh == null)
                    break;

                    var invocationList = eh.GetInvocationList().Where(x =>
                        Equals(x.Target, info.Key) &&
                        x.Method == info.Value);

                foreach (var myDeligate in invocationList)
                {
                    if (eh == null)
                        break;

                    // I HAVE A PROBLEM HERE>>
                    eh -= (EventHandler) myDeligate;
                    // RESULT: eh is null BUT MenuItemSelectionChanged is not null
                }
            }
        }
    ); 
}

ModifyEventHandler now "returns" a reference to the handler, so all changes to it are passed to MenuItemSelectionChanged.

Upvotes: 1

Related Questions