コルーチンを使用せずにこれを実行できるかどうか疑問に思っていました:
private void GetAll()
{
if (_refreshA)
{
collA = new ObservableCollection(GetA<A>());
_refreshA = false;
}
if (_refreshB)
{
collB = new ObservableCollection(GetB<B>(param))
_refreshB = false;
}
if (_refreshC)
{
collC = new ObservableCollection(GetC<C>())
_refreshC = false;
}
}
CollA、ColB、および CollC は UI スレッドで使用されます。GetAll を UI とは異なるスレッドで実行する必要があり、GetA()、GetB(param)、および GetC() を (並列ではなく) 次々に実行する必要があります。
結果は次のようになります (3 つの _refreshX がすべて true の場合):
create new thread
execute GetA() on new thread
wait for data to arrive
update UI collection with new data
create new thread
execute GetB(param) on new thread
wait for data to arrive
update UI collection with new data
create new thread
execute GetC() on new thread
wait for data to arrive
update UI collection with new data
これは TPL でのみ行うことができますか、それともコルーチンも使用する必要がありますか?
編集: async await は .NET 4 では使用できないという間違った印象を持っていたため、svick と Adam Robinson が指摘したので、async await を使用してこれを達成しようとします。
System.Diagnostics.Debug.WriteLine(string.Format("Loading data started. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
IsBusy = true;
//Task.Factory.StartNew(() => GetDataBatch()); // UI is responsive
GetDataBatch(); // UI is not freezed (it is shown), but it is not responsive
System.Diagnostics.Debug.WriteLine(string.Format("Loading data completed. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
private async Task GetAll()
{
if (_refreshA)
{
collA = new ObservableCollection(await Task.Run(() => GetA<A>()));
_refreshA = false;
System.Diagnostics.Debug.WriteLine(string.Format("GetA items loaded. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
}
if (_refreshB)
{
collB = new ObservableCollection(await Task.Run(() => GetB<B>(param)));
_refreshB = false;
System.Diagnostics.Debug.WriteLine(string.Format("GetB items loaded. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
}
System.Threading.Thread.Sleep(10000);
if (_refreshC)
{
collC = new ObservableCollection(await Task.Run(() => GetC<C>()));
_refreshC = false;
System.Diagnostics.Debug.WriteLine(string.Format("GetC items loaded. Thread: {0}, {1}", System.Threading.Thread.CurrentThread.GetHashCode(), DateTime.Now));
}
}
結果は次のとおりです。
Loading data started. Thread: 9, 15-Oct-12 02:35:00
Loading data completed. Thread: 9, 15-Oct-12 02:35:00
GetA items loaded. Thread: 9, 15-Oct-12 02:35:00
GetB items loaded. Thread: 9, 15-Oct-12 02:35:01
GetC items loaded. Thread: 9, 15-Oct-12 02:35:11
問題: UI はフリーズしていません (ビューは表示されています) が、応答しません。たとえば、メニュー項目の上にマウスを置いても何も起こりません。データの読み込み中に表示されるテンプレート (ビジー テンプレート) があり、何が起こっているかをユーザーに示す必要があります。このテンプレートは表示されていません。描画するのに十分な CPU 時間がないようです。このコードを使用する場合:
Task.Factory.StartNew(() => GetDataBatch()); // UI is responsive
//GetDataBatch(); // UI is not freezed (it is shown), but it is not responsive
その後、UI は応答し、ビジー データ テンプレートが画面に表示されますが、問題は、すべてのコレクション データが UI 以外のスレッドに属しているため、UI スレッドから操作を行うことができないことです。
async await はこの問題をどのように処理しますか?