关于注册/取消注册事件的问题

本文关键字:注册 取消 事件 问题 于注册 | 更新日期: 2023-09-27 18:05:41

我正在开发c# WinForms应用程序。它是一个MDI应用程序,其中包含两个表单。在任何时候,只有一个表单将被启用。应用程序有两个线程。一个线程是主线程(驱动GUI的线程)。我还有另一个线程在后台运行,监听来自服务器的TCP消息(这是"Client"线程)。当我得到这些消息时,客户机线程向GUI线程触发一个事件。例如,下面是我如何在代码中布局所有内容的简化示例:

客户端线程中可能发生的事件列表:

    public event EventHandler<ConnectEventArgs> ConnectEvent = delegate { };
    public event EventHandler<DisconnectEventArgs> DisconnectEvent = delegate { };
    public event EventHandler<EdgeMessageEventArgs> EdgeMessageEvent = delegate { };
    public event EventHandler<ServerModeEventArgs> ServerModeEvent = delegate { };
    public event EventHandler<SpreadDataEventArgs> SpreadDataEvent = delegate { };

表单#1注册事件:

        m_Client.ConnectEvent               += new EventHandler<ConnectEventArgs>(OnConnectEvent);
        m_Client.DisconnectEvent            += new EventHandler<DisconnectEventArgs>(OnDisconnect);
        m_Client.EdgeMessageEvent           += new EventHandler<EdgeMessageEventArgs>(OnEdgeMessageEvent);

表单#2注册事件:

        m_Client.ConnectEvent += new EventHandler<ConnectEventArgs>(OnConnectEvent);
        m_Client.DisconnectEvent += new EventHandler<DisconnectEventArgs>(OnDisconnect);
        m_Client.SpreadDataEvent += new EventHandler<SpreadDataEventArgs>(OnSpreadDataEvent);

主窗体(MDI窗口)注册一个事件:

        m_Client.ServerModeEvent    += new EventHandler<ServerModeEventArgs>(OnServerModeEvent);

应用程序启动时,用户连接到服务器。一旦客户端连接到服务器,就会触发ConnectEvent。在它被触发之后,一个ServerModeEvent被触发。这将决定在应用程序中使用哪种表单。我遇到的问题是如何以线程安全的方式在这些表单中注册/取消注册事件。

我最初的想法是在启动时禁用这两个表单,等待用户连接到服务器,然后根据服务器模式只启用其中一个表单。这种方法的问题是,在特定表单上注册事件的过程不是线程安全的,因为客户端线程可能会在表单注册某些事件时触发事件。

我的下一个想法是提前注册两个表单中的所有事件,然后连接到服务器,然后禁用其中一个表单。问题类似于被禁用的表单正在取消注册事件,而它可能从客户端线程接收事件。

我听说过"弱事件",并认为这可能是我问题的答案。我真的不知道如何在我的应用程序中实现这一点。对我遇到的问题有什么想法吗?我可以使用弱事件吗?别的吗?

关于注册/取消注册事件的问题

如果您使用控件。调用发送事件从你的客户端线程到你的UI线程,客户端线程将被阻塞,直到UI线程完成处理事件;这意味着当你在UI线程中设置事件处理程序时,你没有可能引发异步事件。(这是假设你的客户端线程实际上是一个单独的线程,它本身不是异步的。)

如果您使用Control。然而,当UI线程处理事件时,客户端线程不会阻塞。这样做的好处是客户端线程不必等待UI,但缺点是您可能需要提前在客户端对象上注册所有事件,因为它可能在UI线程有机会为其设置事件处理程序之前转过来并触发事件。事实上,客户端线程甚至可以在UI线程有机会开始处理第一个事件之前发送多个事件(在这种情况下,它们被UI线程排队并按顺序处理)。

那么,解决方案就是在需要客户端同步处理事件时使用Invoke;