2010-11-18 3 views
0

私の質問にはイベントが含まれており、クラス内のイベントをトリガしています。このクラスは私のTCP機能をラップし、これを実現するためにTcpListenerを使用しています。私はいくつかのTCPのものは、以下の例から消失する可能性が実現するが、私はできるだけシンプルなものを作りたい:#2.0サンプルCでのAsyncCallbackからのトリガーイベント

class MyTcpClass 
{ 
    public delegate void ClientConnectHandler(Socket client, int clientNum); 

    public event ClientConnectHandler ClientConnect; 

    private Socket wellKnownSocket; 
    private Socket[] clientSockets = new Socket[MAX_CLIENTS]; 
    private int numConnected = 0; 

    private void OnClientConnect(Socket client, int clientNum) 
    { 
     if (ClientConnect != null) 
     ClientConnect(client, clientNum); 
    } 

    public void StartListening() 
    { 
     //initialize wellKnownSocket 
     //... 
     wellKnownSocket.BeginAccept(new AsyncCallback(internal_clientConnect); 
    } 

    public void internal_clientConnect(IAsyncResult ar) 
    { 
     //Add client socket to clientSocket[numConnected] 
     //numConnected++; 
     //... 
     wellKnownSocket.EndAccept(ar); 

     OnClientConnect(clientSocket[numConnected], numConnected);   
     //error: event happens on different thread!! 
    } 
} 

class MainForm 
{ 
    void Button_click() 
    { 
     MyTcpClass mtc = new MyTcpClass(); 
     mtc.ClientConnect += mtc_ClientConnected; 
    } 

    void mtc_clientConnected(Socket client, int clientNum) 
    { 
     ActivityListBox.Items.Add("Client #" + clientNum.ToString() + " connected."); 
     //exception: cannot modify control on seperate thread 
    } 
} 

C

私は私の質問があると思い、あまりにもこのパターンを壊すことなく、多くの意味がありますか?また、誰かがより優雅なソリューションを持っている場合は、歓迎します。

理論

class MainForm 
{ 
    public MainForm() 
    { 
     MyTcpClass mtc = new MyTcpClass(); 
     MyTcpClass2 mtc2 = new MyTcpClass2(this); 
     //this version holds a Form handle to invoke the event 

     mtc.ClientConnect += mtc_uglyClientConnect; 
     mtc2.ClientConnect += mtc2_smartClientConnect; 
    } 

    //This event is being called in the AsyncCallback of MyTcpClass 
    //the main form handles invoking the control, I want to avoid this 
    void mtc_uglyClientConnect(Socket s, int n) 
    { 
     if (mycontrol.InvokeRequired) 
     { 
     //call begininvoke to update mycontrol 
     } 
     else 
     { 
     mycontrol.text = "Client " + n.ToString() + " connected."; 
     } 
    } 

    //This is slightly cleaner, as it is triggered in MyTcpClass2 by using its 
    //passed in Form handle's BeginInvoke to trigger the event on its own thread. 
    //However, I also want to avoid this because referencing a form in a seperate class 
    //while having it (the main form) observe events in the class as well seems... bad 
    void mtc2_smartClientConnect(Socket s, int n) 
    { 
     mycontrol.text = "Client " + n.ToString() + " connected."; 
    } 
} 

答えて

0

あなたはMyTcpClass2のコードを投稿できませんでしたが、私はあなたがで取得しているか見てかなり確信しています。

いいえ、私は第2の方法ではありません。たとえば、他の何かがそのイベントに同時にバインドする必要がある場合、別のスレッドで強制的に実行するためです。要するに、イベントを受け取るメソッドは、必要なスレッドが必要なコードを実行する責任があります。イベントを発生させるメカニズムは、レシーバが必要とするあらゆる種類の奇妙なスレッディングにはまったく気付かないといけません。複数のイベントバインディングシナリオを複雑にするのとは別に、クロススレッド呼び出しのロジックを、それが属していないクラスに移動します。 MyTcpClassクラスは、TCPクライアント/サーバーの問題を処理することに重点を置くべきであり、Winformsスレッドを悩ます必要はありません。

+0

最初の例をお勧めします。ここでは、呼び出しを使用してMainFormのイベントハンドラ内のwinformコントロールにアクセスしますか?私は、MyTcpClassがどのスレッド上にあるのか気付かないでくださいが、MyTcpClassには、クライアントとの非同期コールバック関係があります。私は、MyTcpClassが作成されたスレッドではなく、スレッドでイベントをトリガーしたいと思っています。私はあなたの意見を見て、それに同意しますが、Microsoft自身がprogresschangedイベントで "backgroundworker"という同様のイベントをモデル化します。 –

+0

@Tom:問題は、このスレッドモデルがWinformsに特有であることです。クラスが作成されたスレッドでイベントハンドラを呼び出すことさえできないことがあります。 (スレッドが終了した場合はどうなりますか?) – cdhowie

関連する問題