1

たとえば、ビジネス オブジェクトがありますPerson

class Person : INotifyPropertyChanged
{
    string Name { get; set; }
    DateTime DateOfBirth { get; set; }
}
// ^ abbreviated for better legibility; implementation would be trivial

そして、このクラスのオブジェクトにデータ バインドされた Winforms UI コントロールがいくつかあります。

Person somePerson = ...;
nameTextBox.DataBindings.Add("Text", somePerson, "Name");
dobDatePicker.DataBindings.Add("Value", somePerson, "DateOfBirth");

現在、変更を行っていますが、実装somePersonしたおかげでINotifyPropertyChanged、それらの変更が UI に反映されています。ここまでは順調ですね。

ここで私の問題:ワーカー スレッド (つまり、UI スレッドではない) に変更を加えるとsomePerson、たとえばバックグラウンド操作として DB からデータをロードしているために、データ バインディングが更新を試みるため、例外が発生する可能性があります。コントロールは、UI スレッドでのみ発生することが許可されています。

これは、UI 要素を呼び出して、ビジネス オブジェクトを更新できるかどうかを確認する必要があることを意味します。これは、アプリケーションの論理階層化に違反しInvokeRequiredているように思えます。

理想的には、ビジネス オブジェクトが UI にデータ バインドされているかどうかを気にせずに、ビジネス オブジェクトを変更できるようにしたいと考えています。これは、Winforms のデータ バインディングで何らかの形で可能ですか?

4

1 に答える 1

3

これはあなたの質問に答えませんが、私はこの問題を避けるために可能な限り努力します。

データバインディングが存在するため、ビジネスオブジェクトを更新できるコードは、GUIスレッドで実行されているコードのみであることを確認します。

非同期操作の場合、次のパターンを採用します。

  1. 作業をバックグラウンドに送信します。GUIスレッドから非同期操作(スレッドプールアイテムなど)をトリガーします。プレーンデータ型のみをスレッドプールに渡し、プレーンデータ型のみを受け取ります。スレッドプールでビジネスオブジェクトが使用されている場合は、それらが新しいもの(まだデータバインドされていない)であるか、元のオブジェクトのクローンである(同時アクセスを回避するため)ことを確認してください。
  2. 作業を実行して結果を取得します。バックグラウンドスレッドで非同期操作を実行します。バックグラウンドスレッドコードは、GUIによって与えられた「安全な」オブジェクトを所有します。アプリケーションの他の部分との相互作用はありません。
  3. 結果をGUIで解凍します。非同期操作が終了すると、GUIスレッドで「Iamcomplete」イベントがトリガーされます。それに応じて、GUIスレッドは、バックグラウンド操作からの結果をアンパッケージし、それらをメインのビジネスオブジェクトにマージして戻すことができます。これは、同時アクセスを処理しないという知識で安全です。

System.Threading.Tasks.Task上記の手順のほとんどを抽象化したものとして、このクラスをお勧めします。.NET 4.0の新機能ですが、.NET3.5アプリの個別のダウンロードとしても利用できます。

ステップ(1)と(2)は、Taskクラスがカスタマイズなしで行うことです。(3)Taskは、バックグラウンドスレッド内から別のものを生成TaskScheduler.FromCurrentSynchronizationContextし、スケジューラーとして指定することで実現できます。FromCurrentSynchronizationContext(バックグラウンドスレッドからではなく、ステップ(1)でGUIスレッドから呼び出す必要があります。)

于 2010-08-01T10:38:00.610 に答える