Tasking という名前のコンポーネント (私は変更できません) があるとします。このコンポーネントは、「DoTask」メソッドを公開します。このメソッドは、時間のかかる計算を実行し、イベント TaskCompleted を介して結果を返します。通常、これはユーザーが結果を取得した後に閉じる Windows フォームで呼び出されます。
私の特定のシナリオでは、一部のデータ (データベース レコード) を TaskCompleted で返されたデータに関連付け、それを使用してデータベース レコードを更新する必要があります。
イベントが処理されたときに通知するために AutoResetEvent の使用を調査しました。問題は、AutoResetEvent.WaitOne() がブロックされ、イベント ハンドラーが呼び出されないことです。通常、AutoResetEvents は別のスレッドで呼び出されるため、イベント ハンドラーが呼び出すメソッドと同じスレッド上にあることを意味すると思います。
基本的に、結果がイベントを介して返される非同期呼び出しを、イベントが処理され、結果が両方のイベント ハンドラーにアクセス可能な場所に配置されるまでブロックすることにより、同期呼び出し (つまり、別のクラスから DoSyncTask を呼び出す) に変えたいと考えています。および非同期呼び出しを開始したメソッドを呼び出したメソッド。
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
Application.Run が呼び出されず、ApplicationContext オブジェクトが使用できないウィンドウ サービスで、その動作を複製する必要があるだけです。