6

コンソールまたは GUI の 2 つのモードを持つ WinForms アプリを作成しています。同じソリューション内の 3 つのプロジェクト。1 つはコンソール アプリ用、1 つは UI フォーム用、3 つ目は 2 つのインターフェイスが両方とも接続するロジックを保持します。コンソール アプリは非常にスムーズに動作します。

ユーザー選択を保持するモデルでIList<T>、 T がローカル オブジェクトでありStep、 を実装INotifyPropertyChangedしているため、UI では DataGridView にマウントされます。実行時には問題なく、オブジェクトの初期状態が画面に反映されます。

Stepオブジェクトは順番に実行されるタスクです。一部のプロパティは変更され、IList に反映されて DataGridView に渡されます。

UI バージョンでのこのアクションは、イベントを UI に戻す BackgroundWorker を作成することによって行われます。do it は、結果 (実行中、NotRun、OK、NotOK、警告など) を示す列挙型でStepあるオブジェクトと、メッセージを示す文字列 (ステップが実行されたが、期待どおりではないため、つまり、警告があるため) を生成します。StepResult)。通常、アクションにはデータベースとのやり取りが含まれますが、デバッグ モードではランダムに結果を生成します。

メッセージが null の場合は問題ありませんが、次のような応答を生成すると:

StepResult returnvalue = new StepResult(stat, "completed with caveat")

DataGridView が作成されたスレッド以外のスレッドからアクセスされているというエラーが表示されます。(私はこれを、必要に応じて呼び出しを処理するカスタム ハンドラーに渡しています。おそらくそうではないでしょうか?)

次に、たとえば乱数を使用して、一意の応答を生成した場合r:

StepResult returnvalue = new StepResult(stat, r.ToString());

アクションは問題なく成功し、数値は DataGridView にきれいに書き込まれます。

私は困惑しています。どういうわけか文字列リテラルの問題だと思いますが、誰かがより明確な説明を思い付くことができますか?

4

3 に答える 3

4

あなたはあなた自身の質問に答えました:-

DataGridView が作成されたスレッド以外のスレッドからアクセスされているというエラーが表示されます。

WinForms は、フォームとコントロールで実行されるすべてのアクションが、フォームが作成されたスレッドのコンテキストで実行されることを主張します。この理由は複雑ですが、基礎となる Win32 API に大きく関係しています。詳細については、The Old New Thingブログのさまざまなエントリを参照してください。

InvokeRequired メソッドと Invoke メソッドを使用して、コントロールが常に同じスレッドからアクセスされるようにする必要があります (疑似コード風)。

object Form.SomeFunction (args)
{
  if (InvokeRequired)
  {
    return Invoke (new delegate (Form.Somefunction), args);
  }
  else
  {
    return result_of_some_action;
  }
}
于 2008-10-14T08:10:09.897 に答える
3

イベント サブスクリプションを介して UI バインディングを行っているため、これが役立つ場合がありますBindingList<T>これは、通知が UI スレッドに自動的にマーシャリングされるようにサブクラス化する方法を示す、私が少し前に書いた例です。

同期コンテキストがない場合 (つまり、コンソール モード)、単純な直接呼び出しに戻るため、オーバーヘッドはありません。UI スレッドで実行する場合、これは基本的に を使用することに注意してくださいControl.Invoke。デリゲートが UI スレッド上にある場合は、それ自体がデリゲートを直接実行するだけです。そのため、データが非 UI スレッドから編集されている場合にのみスイッチがあります - 必要なものを突き出します ;-p

于 2008-10-14T09:28:09.550 に答える
0

この記事を見つけました-「別のスレッドからIBindingListを更新する」-これはBindingListに責任の指を向けました-

BindingList は非同期操作用に設定されていないため、BindingList を制御していたのと同じスレッドから更新する必要があります。

親フォームをISynchronizeInvokeオブジェクトとして明示的に渡し、そのラッパーを作成することでBindingList<T>うまくいきました。

于 2008-10-14T10:48:04.913 に答える