Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Temporarily disable event handler

0.00/5 (No votes)
20 Jul 2013 1  
Temporarily disable event handler.

I was just working on a project where I had to temporarily disable event handler. In my case it was property change notification handler, I wanted to disable it when it was me who changed the property. This is the automatic solution that disables and re-enables event handler:

public class Subscriber
{
    private EventSource _eventSource;
    
    public Subscriber(EventSource source)
    {
        _eventSource = source;
        _eventSource.PropertyChanged += Source_PropertyChanged;
    }
    
    private void Source_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //
    }   

    public void DoWithoutEvents()
    {
        using (new DisableEvent(_eventSource, this, "Source_PropertyChanged"))
        {
            // Source_PropertyChanged function will not be called inside this block
            _eventSource.Property = 1;
        }
    }
}

It works on single objects and on collections.

And here is the code:

internal class ResubscribeInfo
{
    public EventInfo Evnt { get; private set; }
    public object EventSource { get; private set; }
    public Delegate ToBeResubscribed { get; private set; }

    public ResubscribeInfo(EventInfo evnt, object eventSource, Delegate toBeResubscribed)
    {
        Evnt = evnt;
        EventSource = eventSource;
        ToBeResubscribed = toBeResubscribed;
    }
}

public class DisableEvent : IDisposable
{
    private static BindingFlags _privatePublicStaticInstance = 
        BindingFlags.IgnoreCase | 
        BindingFlags.NonPublic | 
        BindingFlags.Public | 
        BindingFlags.Instance | 
        BindingFlags.Static |
        BindingFlags.FlattenHierarchy;

    private List<ResubscribeInfo> _resubscribeInfo = new List<ResubscribeInfo>();

    public DisableEvent(object eventSource, object eventSubscriber, string handlerName)
    {
        if (eventSource == null || eventSubscriber == null || 
                   string.IsNullOrEmpty(handlerName))
            throw new ArgumentNullException();

        var tSource = eventSource.GetType();
        var tSubscriber = eventSubscriber.GetType();

        //

        MethodInfo targetMethod = GetMethod(tSubscriber, handlerName);
        if (targetMethod == null)
            throw new InvalidOperationException("Method " + handlerName + " was not found");

        //

        if (!InternalDisable(eventSource, eventSubscriber, targetMethod, tSource))
        {
            // if it is enumerable, disable event on all elements
            if (eventSource is IEnumerable)
            {
                tSource = null;

                foreach (var el in eventSource as IEnumerable)
                {
                    if (tSource == null) tSource = el.GetType();

                    InternalDisable(el, eventSubscriber, targetMethod, tSource);
                }
            }
        }
    }

    public void Dispose()
    {
        if (_resubscribeInfo != null)
        {
            foreach (var resub in _resubscribeInfo)
            {
                resub.Evnt.GetAddMethod(true).Invoke(
                  resub.EventSource, new object[] {resub.ToBeResubscribed});
            }
        }

        _resubscribeInfo = null;
    }

    private bool InternalDisable(object eventSource, 
      object eventSubscriber, MethodInfo targetMethod, Type tSource)
    {
        bool found = false;

        foreach (var e in tSource.GetEvents())
        {
            var field = GetField(tSource, e.Name);
            var deleg = (Delegate) field.GetValue(eventSource);

            if (deleg != null)
            {
                var invocList = deleg.GetInvocationList();

                var toBeUnsubscribed = invocList.FirstOrDefault(
                  x => x.Target == eventSubscriber && x.Method == targetMethod);

                if (toBeUnsubscribed != null)
                {
                    e.GetRemoveMethod(true).Invoke(eventSource, new object[] {toBeUnsubscribed});
                    _resubscribeInfo.Add(new ResubscribeInfo(e, eventSource, toBeUnsubscribed));

                    found = true;
                    break;
                }
            }
        }

        return found;
    }

    private FieldInfo GetField(Type type, string name)
    {
        if (type.IsInterface)
        {
            var considered = new List<Type>();
            var queue = new Queue<Type>();
            considered.Add(type);
            queue.Enqueue(type);
            while (queue.Count > 0)
            {
                var subType = queue.Dequeue();
                foreach (var subInterface in subType.GetInterfaces())
                {
                    if (considered.Contains(subInterface)) continue;

                    considered.Add(subInterface);
                    queue.Enqueue(subInterface);
                }

                var prop = subType.GetField(name, _privatePublicStaticInstance);
                if (prop != null) return prop;
            }
        }

        var retval = type.GetField(name, _privatePublicStaticInstance);
        if (retval == null)
        {
            var btype = type.BaseType;
            if (btype != null) retval = GetField(btype, name);
        }

        return retval;
    }
    private MethodInfo GetMethod(Type type, string name)
    {
        while (type != null)
        {
            var method = type.GetMethod(name, _privatePublicStaticInstance);
            if (method != null) return method;
            type = type.BaseType;
        }

        return null;
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here