2

その「ClientSocket.cs」のようなクラスがあります

  class ClientSocket {
     public delegate void ConnectHandler(object sender, EventArgs e);
     public event ConnectHandler ConnectEvent = delegate { };

     protected void OnConnectEvent(EventArgs e) {
        ConnectHandler ev = ConnectEvent;
        ev(this, e);
    }

  }

そして別のクラス「myForm.cs」

public partial class myForm : Form {
    private ClientSocket client;

    private void button1_Click(object sender, EventArgs e) {
        client = new ClientSocket();
        client.ConnectEvent += myForm_OnConnectEvent;

        client.connect();
    }


    // Handler for ConnectEvent
    private void myForm_OnConnectEvent(object sender, EventArgs e) {
        //this.BeginInvoke((MethodInvoker)delegate { writeLog("Connected"); }); 

        writeLog("Connected");
    }

    // Function that write a log string to a TextBox
    public writeLog(string log) {
        guiTextBox.AppendText(log);
    }
  }

ここで質問です。BeginInvoke で writeLog を呼び出すか、直接呼び出すようにしています。guiTextBox への書き込み時に InvalidOperationException が発生することがあります。そのメッセージを受け取る理由がわかりません。イベントは ClientSocket オブジェクトによって発生しますが、イベント ハンドラーはメインの UI スレッド (myForm) に関連しています。

クラスの各 EventHandler に BeginInvoke/Invoke を使用しないようにすることはできますか?


編集:違いはわかりました。イベントを呼び出すためのベストプラクティスを理解しようとしています。

BASE クラス(その場合は ClientSocket) でイベントを RAISING するときに BeginInvoke/Invoke メソッドを配置する必要がありますか?

    protected void OnConnectEvent(EventArgs e) {
        ConnectHandler ev = ConnectEvent;

        this.BeginInvoke((MethodInvoker)delegate { ev(this, e);});
    }

または、そのオブジェクトを使用しているときにそれを入れて、そのハンドラーにリスナーを追加する必要があります

    // Handler for ConnectEvent used in GUI (myForm)
    private void myForm_OnConnectEvent(object sender, EventArgs e) {
        this.BeginInvoke((MethodInvoker)delegate { writeLog("Connected"); }); 
    }

乾杯

4

2 に答える 2

3

イベントハンドラは で宣言されていますが、ハンドラを実行するスレッドはクラスmyFormのロジックで定義されています。ClientSocketこれがバックグラウンド スレッドになる場合、イベント ハンドラーはバックグラウンド スレッドから呼び出されるため、BeginInvokeコントロールへのクロススレッド アクセスを避ける必要があります。

言い換えれば、どのタイプのどのメソッドの所属も、このメソッドを実行するスレッドとは関係ありません。これらのもの (型とスレッド) はパラレル ユニバースです。

ちなみに、これを置き換えることができます:

public delegate void ConnectHandler(object sender, EventArgs e);
public event ConnectHandler ConnectEvent = delegate { };

これとともに:

public event EventHandler ConnectEvent;

さらに別のデリゲート型を作成する必要はありません。

于 2013-11-11T21:30:52.230 に答える