简体   繁体   中英

Winforms - Question about registering/unregistering events

I am developing C# WinForms application. It is a MDI application that contains two forms inside of it. At any time, only one of the forms will be enabled. The application has two threads. One thread is the main thread (the thread that is driving the GUI). I also have another thread running in the background that listens for TCP messages from a server (this is the "Client" thread). When I get one these messages, the Client thread fires an event to the GUI thread. So for example, here's a simplified example of how I have everything laid out in the code:

List of possible events in Client thread:

    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 { };

Form #1 registering for events:

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

Form #2 registering for events:

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

The main form (the MDI window) registers for one event:

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

When the application starts up, the user connects to the server. As soon as the client is connected to the server, a ConnectEvent is fired. Right after this is fired, a ServerModeEvent is fired. This will basically determine which form will be used in the application. The issue I am running into is how to do all of the registering/unregistering of events in these forms in a thread-safe manner.

My initial thought was to keep both forms disabled on start up, wait for the user to connect to the server, and then enable only one of the forms based on the server mode. The problem with this approach is that the process of registering for events on the particular form would not be thread-safe because the client thread could potentially fire an event while the form is registering for certain events.

My next thought was to register for all events in both forms ahead of time, then connect to the server, and then disable one of the forms. The problem is similar in that the form being disabled is unregistering events while it could potentially receive an event from the client thread.

I have heard of "weak events" and was thinking this might be the answer to my problem. I don't really know how to implement this in my application though. Any thoughts about the issue I am having? Could I use weak events? Something else?

If you use Control.Invoke to send events from your client thread to your UI thread, the client thread will be blocked until the UI thread is done handling the event; which means you'd have no possibility of an asynchronous event being raised while you're getting your event handlers set up in the UI thread. (This is assuming your client thread is actually a single thread that isn't asynchronous within itself.)

If you use Control.BeginInvoke , however, the client thread doesn't block while the UI thread handles the event. The benefit is that the client thread never has to wait for the UI, but the tradeoff is that you'd likely need to have all your events registered on the client object in advance, since it could turn around and fire off an event before the UI thread has had a chance to get event handlers set up for it. In fact, the client thread could send multiple events before the UI thread even gets a chance to begin to handle the first (in which case, they're queued up and handled in order by the UI thread).

The solution, then, is to use Invoke when you need synchronous handling of an event by the client; and BeginInvoke when you don't.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM