代码之家  ›  专栏  ›  技术社区  ›  torvin Mayank

微软Win32。SystemEvents事件不能与最弱的EventManager一起使用

  •  1
  • torvin Mayank  · 技术社区  · 8 年前

    当我这样做的时候

    WeakEventManager<SystemEvents, EventArgs>
        .AddHandler(null, nameof(SystemEvents.DisplaySettingsChanged), OnDisplaySettingsChanged);
    

    我的 OnDisplaySettingsChanged 从未接到电话。但是,如果我改为通过 SystemEvents.DisplaySettingsChanged += OnDisplaySettingsChanged 一切正常。

    发生什么事了?

    1 回复  |  直到 8 年前
        1
  •  2
  •   torvin Mayank    8 年前

    结果是 WeakEventManager 的故障。当触发事件时,它意味着 source 将是 null 对于静态事件源(代码摘录自 reference source ):

    protected void DeliverEvent(object sender, EventArgs args)
    {
        ListenerList list;
        object sourceKey = (sender != null) ? sender : StaticSource;
        ...
    

    但是 sender 永远不会 无效的 对于 SystemEvents 。而是传递 系统事件 ,则, 弱势管理者 然后假设它是以前不知道的另一个实例,并且不调用处理程序。

    以下是我想到的解决方法:

    class EventProxy
    {
        private readonly Action<EventHandler> _subscribe;
        private readonly Action<EventHandler> _unsubscribe;
    
        public EventProxy(Action<EventHandler> subscribe, Action<EventHandler> unsubscribe)
        {
            _subscribe = subscribe;
            _unsubscribe = unsubscribe;
        }
    
        private EventHandler _event;
        public event EventHandler Event
        {
            add
            {
                if (_event == null)
                    _subscribe(OnEvent);
                _event += value;
            }
            remove
            {
                // ReSharper disable once DelegateSubtraction
                _event -= value;
                if (_event == null)
                    _unsubscribe(OnEvent);
            }
        }
    
        private void OnEvent(object sender, EventArgs args)
        {
            _event?.Invoke(this, args);
        }
    }
    

    用法示例:

    var proxy = new EventProxy(h => SystemEvents.DisplaySettingsChanged += h, h => SystemEvents.DisplaySettingsChanged -= h);
    WeakEventManager<EventProxy, EventArgs>.AddHandler(proxy, nameof(EventProxy.Event), OnDisplaySettingsChanged);
    

    一些解释:

    • 系统事件 强烈引用 EventProxy ,它持有对处理程序的弱引用(通过 弱势管理者 )
    • 什么时候 弱势管理者 订阅内部事件 AddHandler ,代理订阅原始事件
    • 事件代理 充当静态事件和处理程序之间的代理,在原始事件激发时调用处理程序
    • 收集处理程序后, 弱势管理者 将最终运行清理,发现处理程序已死亡并取消订阅
    • 这将导致代理从原始事件中取消订阅,并最终由GC收集