EventHandler 冒泡

EventHandler bubbling up

我想通过 classes 发送消息。我使用了事件并这样做了:

public class TopLevel{
    public event EventHandler<string> Message;
    public MiddleLevel mid;

    public TopLevel()
    {
        mid.Message += (s, e) => { Message(s, e) };
    }
} 

public class MiddleLevel{
    public event EventHandler<string> Message;
    public BottomLevel bottom;

    public MiddleLevel()
    {
        bottom.Message += (s, e) => { Message(s, e) };
    }
}

public class BootomLevel{
    public event EventHandler<string> Message;

    public void DoSomething()
    {
        Message?.Invoke(this, "I did it.");
    }
}

public class Handler{
    public void HandleEvent(TopLevel top)
    {
        top.Message += PrintMessage;
    }

    public void PrintMessage(object sender, string message)
    {
        Console.WrteLine(message);
    }
}

还尝试将构造函数更改为 lambda 表达式,如下所示:

public class TopLevel{
    public event EventHandler<string> Message;
    public MiddleLevel mid;

    public TopLevel()
    {
        mid.Message += (s, e) => { Message?.Invoke(s, e); };
    }
} 

public class MiddleLevel{
    public event EventHandler<string> Message;
    public BottomLevel bottom;

    public MiddleLevel()
    {
        bottom.Message += (s, e) => { Message?.Invoke(s, e); };
    }
}

public class BootomLevel{
    public event EventHandler<string> Message;

    public void DoSomething()
    {
        Message?.Invoke(this, "I did it.");
    }
}

public class Handler{
    public void HandleEvent(TopLevel top)
    {
        top.Message += PrintMessage;
    }

    public void PrintMessage(object sender, string message)
    {
        Console.WrteLine(message);
    }
}

以上代码不打印任何消息。即使我在 MiddleLevel class 中处理事件,我仍然没有收到消息。我认为这是因为消息调用是在构造函数中进行的(即使 linq 采石场会自行更新)?如果我直接从 BottomLevel class 处理 Handle class 中的事件,它显然有效。但我需要冒泡消息,我想不出任何其他方法,因为 classes 是如何构建的。是否可以使用标准事件处理程序 class 来实现我的想法?如果是这样怎么办?我是否应该像在我提到的其中一个网站上那样自己做一个活动 class?

我参考了这些网站:

What is the preferred way to bubble events?

https://www.carlosble.com/2016/04/event-bubbling-in-c/

更新的答案:

如果您想要触发 'Handler',您必须确保 'BottomLevel' 属于传递给处理程序的 'TopLevel' class 的层次结构,这可以通过依赖注入 (DI) 来完成。

如果 'BottomLevel' 实例化它自己的 classes(无 DI),那么它将不知道 'Handler',因此永远不会触发处理程序。

如果您注释掉 DI 设置并取消注释 'BottomLevel' 实例化,您可以看到不同的行为。

   class Program
    {
        static void Main(string[] args)
        {
            //setup the classes (dependency injection)
            TopLevel topLevel = new TopLevel();
            MiddleLevel middleLevel = new MiddleLevel(topLevel);
            BottomLevel bottomLevel = new BottomLevel(middleLevel);

            //set up the handler
            Handler h = new Handler(topLevel);
            
            //using this will not link to 'Handler' as there is no relation between this bottom and top
            //BottomLevel bottomLevel = new BottomLevel(); 

            //trigger the bottom class
            bottomLevel.TriggerBottom();
            //or
            bottomLevel.DoSomething(null, "call from main");

            Console.ReadLine();
        }
    }

    public class Handler
    {
        TopLevel _topLevel;
        public Handler(TopLevel topLevel)
        {
            if (topLevel != null)
                _topLevel = topLevel;

            _topLevel.Message += _topLevel_Message;
        }

        private void _topLevel_Message(object sender, string e)
        {
            Console.WriteLine($"handler triggered : {e}");
        }
    }

    public class TopLevel
    {
        public event EventHandler<string> Message;

        public TopLevel()
        { }

        public void TriggerTop()
        {
            Message?.Invoke(this, "origin top");
        }

        public void DoSomething(object sender, string e)
        {
            Console.WriteLine($"Do something at top : {e}");
            Message?.Invoke(this, e);
        }
    }

    public class MiddleLevel
    {
        TopLevel _TopLevel;
        public event EventHandler<string> Message;

        public MiddleLevel(TopLevel topLevel) : this()
        {
            _TopLevel = topLevel;
        }
        public MiddleLevel()
        {
            if (_TopLevel == null)
                _TopLevel = new TopLevel();
            //subscribe this message to bottom message event method
            Message += (s, e) => { _TopLevel.DoSomething(s, e); };
        }

        public void TriggerMiddle()
        {
            Message?.Invoke(this, "origin middle");
        }

        public void DoSomething(object sender, string e)
        {
            Console.WriteLine($"do something in middle : {e}");

            //invoke the event(s)        
            Message?.Invoke(sender, e);
        }
    }

    public class BottomLevel
    {
        MiddleLevel _MidLevel;
        public event EventHandler<string> Message;

        public BottomLevel(MiddleLevel midLevel) : this()
        {
            _MidLevel = midLevel;
        }

        public BottomLevel()
        {
            if (_MidLevel == null)
                _MidLevel = new MiddleLevel();

            ////here you assign it
            Message += (s, e) => { _MidLevel.DoSomething(s, e); };

        }

        public void TriggerBottom()
        {
            DoSomething(this, "origin bottom");
        }

        public void DoSomething(object sender, string e)
        {
            Console.WriteLine($"do something at bottom : {e}");
            Message?.Invoke(sender, e);
        }
    }