相关文章推荐
急躁的手套  ·  ondragover 事件 | ·  2 月前    · 
安静的包子  ·  JDBC写入postgresql ...·  2 年前    · 
严肃的松树  ·  electron使用child_proces ...·  3 年前    · 
小胡子的斑马  ·  vue.js 箭头函数 - 简书·  3 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have an application that consumes LayoutUpdated-events and need to register them weak. Here is the problem, I got stuck on, during implementation of the WeakEventManager

internal class WeakLayoutUpdatedManager : WeakEventManager
    private void OnLayoutUpdated(object sender, EventArgs e)
        // NOTE: received sender is always null (by design of LayoutUpdated) 
        base.DeliverEvent(sender, e);

That's what happens:

  • we always receive null as sender (by design of LayoutUpdated)
  • that null gets passed into DeliverEvent
  • DeliverEvent can not lookup the correct ListenerList, because it needs a sender != null as key
  • the failing lookup in WPF: WeakEventManager // DeliverEvent // Line: 359

    object sourceKey = (sender != null) ? sender : StaticSource;
    list = (ListenerList)Table[this, sourceKey];
    

    My question is: is there a way to weak-register to LayoutUpdated event?

    I'm not interested in the sender-parameter, so it's ok to me that LayoutUpdated always delivers null (my actual implemention with regular "+=" works). But the WeakEventManager base-class relies on the sender-parameter to keep track of the ListenerLists.

    As you have found yourself, null sender breaks WeakEventManager into thinking that this is a static event, which basically makes it incompatible with LayoutUpdated. Since WeakEventManager.DeliverEvent is non-virtual, you cannot really "fix" it.

    So I think your option would be to use a third-party weak event manager, or write one yourself, which shouldn't be that difficult (unless you need a generic solution).

    The idea is to break a hard reference between the event source (UIElement) and the event subscriber (Delegate.Target), which may be achieved by using a mediator class with weak references to the event handler and its target.

    Here is a quick-and-dirty example that would work with events of type EventHandler:

    public class WeakEventListener<TSender>
        private readonly EventHandler _handler;
        private readonly EventInfo _event;
        private readonly WeakReference<object> _target;
        // Helps to keep original EventHandler alive as long as its target isn't GCed.
        private readonly ConditionalWeakTable<object, EventHandler> _targetHandler =
            new ConditionalWeakTable<object, EventHandler>();
        public WeakEventListener(string eventName, EventHandler handler)
            _handler = new EventHandler(DeliverEvent);
            _event = typeof(TSender).GetEvent(eventName);
            _target = new WeakReference<object>(handler.Target);
            _targetHandler.Add(handler.Target, handler);
        public void Add(TSender source) => _event.AddEventHandler(source, _handler);
        public void Remove(TSender source) => _event.RemoveEventHandler(source, _handler);
        private void DeliverEvent(object sender, EventArgs args)
            if (_target.TryGetTarget(out object target) &&
                _targetHandler.TryGetValue(target, out EventHandler handler))
                handler(sender, args);
    

    Which may be used as follows:

    var listener = new WeakEventListener<UIElement>(nameof(LayoutUpdated), OnLayoutUpdated);
    listener.Add(uiElement);
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.