私はストアドアクションの呼び出しリストであるタイマーを持っています。これらのアクションを非同期的に呼び出すようにします。だから、私はCPUバインド操作をタスクにラップし、非同期/動作待ちにしました。ただし、コンボボックスは更新されません。明らかにコンテキストはUIに戻っていませんが、なぜそれを修正するために何をすべきか理解できません。メインフォームでasync/UIスレッドに戻って待たないでください
コード:
public FormMain()
{
InitializeComponent();
pt = new PeriodicTask(() => Execute());
pt.Start();
actions = new List<ActionWrapper>();
actions.Add(new ActionWrapper() { Periodic = false, MyAction = async() => {
bool b = await NetworkOperation();
comboBoxPairs.DataSource = pairs; // this doesn't update combo box
comboBoxPairs.DisplayMember = "Name";
//comboBoxPairs.Refresh(); // this is even crashing app
}});
}
private Task<bool> NetworkOperation()
{
return Task.Run(() => {
// CPU bound activity goes here
return true;
});
}
private void Execute()
{
Parallel.ForEach(actions,
new ParallelOptions { MaxDegreeOfParallelism = 10 },
x => {
x.MyAction();
if (!x.Periodic)
actions.Remove(x);
});
}
Timerクラス:
public class PeriodicTask
{
private System.Threading.Timer timer;
private int dueTime;
private int periodTime;
private Action callBack;
public PeriodicTask(Action cb)
{
callBack = cb;
timer = new System.Threading.Timer(Task, null, Timeout.Infinite, Timeout.Infinite);
dueTime = 100;
periodTime = 5000;
}
public void Start()
{
timer.Change(dueTime, periodTime);
}
public void Stop()
{
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
private void Task(object parameter)
{
callBack();
}
}
これは私がアクションを保持するために使用するラッパークラスです:
public class ActionWrapper
{
public bool Periodic { get; set; }
public Func<Task> MyAction { get; set; }
}
問題は、アクションが任意のスレッドプールスレッドで実行され、WinForms同期コンテキストからの非同期アクションをトリガーしていないことです。待機は、継続が同じ同期コンテキストに戻るという点で機能しますが、Parallel.ForEachはデフォルトのスケジューラ(プール)でタスクをキューに入れるだけなので、WinFormsではありません。また、ネットワーク通話が最初に終了した場合、まだ作成していないため、行が並んでいないという競合条件があります。スリムチャンスは、与えられたが、まだ奇妙に見えます。実は、レースコンディションについては少し無視してください。 –
私は間違っていると思う、コードの少しを誤解していた。 –
'TaskScheduler.FromCurrentSynchronizationContext()'をアクションに渡す必要がありますか?しかし、私はasync/awaitを使用することはできませんし、コンテキストをTPLで自分で変更する必要があります。 – Pablo