0

現在、namedpipeとC#を使用してネットワークプログラムを実装しています。サーバープログラムのmainメソッド内で、クライアントプログラムからメッセージを読み取る「ReadingMessage」という名前のスレッドを開始しました。このスレッドでは、クライアントから返されたメッセージに基づいて、コントロールのプロパティ(テキストボックスのテキスト、ラベルの位置など)を変更する必要があります。したがって、この手順ではクロススレッドエラーが発生しました(「UIスレッド間のReadingMesssage」)。この問題を解決するには2つの方法があることがわかりました

  1. Delegateを使用してコントロールを呼び出します
  2. Form.CheckForIllegalCrossThreadCalls = false;

両方をテストしましたが、問題が1つあります。フォームが最初に開始されたとき、コントロールのプロパティはエラーなしで変更されます。フォームを閉じて2回目に再開しても、コントロールのプロパティは変更されず、エラーメッセージも表示されません。コントロールのプロパティを変更するように指示されているコードへのブレークポイントをキャッチします。コードはスムーズに実行されますが、それでも問題は発生します。

何が問題なのかわかりません。したがって、誰かがこの問題を知っているなら、私に提案してください...

更新:(コードの投稿と私の最初の質問のいくつかのエラーの修正)

スレッドはサーバープログラムのメインメソッドにありません。質問を簡単に説明したかったので、私は間違っていました。ここで、私の質問について詳しく説明します。サーバープログラムのメインフォームには、ボタンクリックイベントが1つあります。

//Main Form
public partial class MainForm : Form
{
    private void btnButton_Click(object sender, EventArgs e)
    {
       AnotherForm aform = new AnotherForm(); //This is the form where threading run
       aform.show();    
    }
}

//AnotherForm
public partial class AnotherForm : Form
{
    private void CargoLoading_Load(object sender, EventArgs e)
    {
        (new System.Threading.Thread(readingMessage)).Start(myPipe);    
    }
}

private void readingMessage(Object myPipeObject) //Read the messages send from the client machine
{
     while (true)
     {
         //Code of serverstream
         SetTextofTextBox1("AnyText"); //Code where the properties of control are instructed to change
     }
}

private void SetTextofTextBox1(string text)
{
     if (this.txtTextBox1.InvokeRequired) //the debugger return false at second time of this form is opened
     {
         SetTextCallback d = new SetTextCallback(SetTextofTextBox1);
         this.Invoke(d, new object[] { text });
     }
     else
     {
          this.txtTextBox1.Text = text;
          this.txtTextBox1.Update();
     }
}

問題が発生するコードはこれだけです。「AnotherForm」を初めて開いたときはOKです。ただし、2回目に再度開かれると、コントロールのプロパティ(TextBox1のテキスト)は影響を受けず、変更されません。そこで、デバッガーControl.InvokeRequiredがこの2回目にfalseを返すことに気づきました。私はプログラマーとしての初心者なので、長い質問をして本当に申し訳ありません。

まだあなたの提案を期待しています...

アップデート2:

最後に私はすべての方法を試しましたが、それは最善の解決策にはなりません。したがって、この状況を回避し、私のような状況に遭遇したときに、コードの一部を別の概念で書き直すことをすべての人に提案したいと思います。

4

2 に答える 2

2

UI を更新するコードを UI スレッドに実行させるには、バックグラウンド スレッドからControl.InvokeRequiredandを使用する必要があります。Control.Invoke

UI スレッドのみがコントロール プロパティに「触れる」ことができるため、バックグラウンド スレッドはそれらを更新できません。

より具体的に言えば、より詳細に興味がある場合に備えて: Windows では、通常、各フォームとコントロールに 1 つ以上の HWND が関連付けられています。HWND は、Windows ウィンドウを表す Windows オペレーティング システム オブジェクトへのハンドルです。

各 HWND は、常に特定のスレッド (それを作成したスレッド) に関連付けられています。その HWND に送信されたすべての Windows メッセージは、そのスレッドのメッセージ キューに到達し、そのスレッドのメッセージ ループによって処理される必要があります。

Controls メソッドに対して一見無害な呼び出しを行うと、これらのメソッドの実装によって、内部で HWND が破棄および作成されることがあります (たとえば、Menu コントロールのサブメニューの作成や Toolbar コントロールへのボタンの追加など)。このような呼び出しを別のスレッドから行うと、HWND が別のスレッドに属し、コントロールのメッセージの処理が中断されます。

そのため、コントロールのメソッドへのすべてのアクセスは、コントロールの HWND を作成したスレッド (たとえば、Control.CreateControl() が呼び出されたスレッド) 以外のスレッドからは禁止されています。

要するに、ほとんどの単純なアプリケーションの場合、ウィンドウを作成するのはメイン スレッドだけなので、フォームとコントロールはメイン スレッドからのみ操作する必要があります。

于 2012-10-23T00:48:04.007 に答える
0

コードを投稿してください。特に、ウィンドウの開閉に使用するコード。

Application.Run()あなたの説明から、バックグラウンド スレッドの実行中にフォームでループを実行していると推測しています。

次に、メッセージ ループを実行せずに、フォームを閉じて新しいフォームを開いている可能性があります。SoControl.Invoke戻りますが、コールバックは UI スレッドによって呼び出されません (これはメッセージをポンピングしていません)。

これは、コードを見ないで推測するだけです。

于 2012-10-23T01:00:19.967 に答える