私の疑似ソリューションについては、投稿の下部を参照してください。
もう一度、私は完全にそして完全にこれに固執しています。私は理解しようとして何時間も費やしました-そしてそうです、コードビハインドのスレッド化について何もせずに、単一のcollectionviewsourceを美しく動作させることができます。
ページに2つのcollectionviewsourcesを追加するだけで、スレッドの問題が発生することに気付いたときのショックを想像してみてください。私は昨夜、C#5のAsyncとMSDNのものを読んで数時間を過ごしましたが、今日仕事に取り掛かり、これを実現する方法を理解できません。
以下のコードは、私が燃やしたので助けを求めて泣き言を言う前に私が行った最後の試みです。おそらく、これを行う方法を理解しようとするのに少し時間がかかりすぎます。1つのcollectionviewsourceを完了してから別のコレクションを開始する必要があることを理解したので、AwaitTask.ContinueWithなどを試して次々にチェーンを試みました。
スレッド内の両方のタスクセットを正しく並べるのは非常に難しいようです。または、私はまだ根本的な何かを誤解しています。
誰かがWPFUIのいくつかのコントロールに非同期でデータを入力する方法をアドバイスできれば、私は非常に感謝しています。
アプリケーション自体は使い捨てのアプリケーションであり、Accessデータベースにリンクされており、適切なコードベースに実装するためにスレッド化を十分に流暢に行えるようにするために使用しています。私はそれから遠く離れています!
より完全なコードサンプルと回答に従って行われた調整で更新されました:
Private Async Sub MainWindowLoaded(sender As Object, e As RoutedEventArgs) Handles MyBase.Loaded
InitializeComponent()
Dim personSetViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("personSetViewSource"), System.Windows.Data.CollectionViewSource)
Dim contactSetViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("contactSetViewSource"), System.Windows.Data.CollectionViewSource)
Dim personList = Await Task.Run(Function() personSet.personList)
personSetViewSource.Source = personList
Dim contactList = Await Task.Run(Function() contactSet.contactList)
contactSetViewSource.Source = contactList
End Sub`
ObservableCollectionExクラス:
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
using (BlockReentrancy())
{
NotifyCollectionChangedEventHandler collectionChanged = this.CollectionChanged;
if (collectionChanged != null)
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
{
DispatcherObject dispObj = nh.Target as DispatcherObject;
if (dispObj != null)
{
Dispatcher dispatcher = dispObj.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
{
NotifyCollectionChangedEventHandler nh1 = nh;
dispatcher.BeginInvoke(
(Action) (() => nh1.Invoke(this,
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset))),
DispatcherPriority.DataBind);
continue;
}
}
nh.Invoke(this, e);
}
}
}
}
イベントオーバーライドが必要なため、このクラスをVBに変換できないことに注意してください。私が試した別のバリエーションですが、スレッドの所有権に再び反することになります。2つのcollectionviewsの問題は解決策になりません。それが、基になるコレクションがそのコレクションに適していないためなのか、それとも実際にはそのように機能することを意図していないためなのかはわかりません。私は近づきますが葉巻はありません。
Dim CarePlanList = Task.Run(Function() CarePlanSet.CarePlanList)
Dim rcpdList = Task.Run(Function() rcpdSet.rcpdList)
Dim tasks() As Task = {CarePlanList, rcpdList}
Dim t = New TaskFactory
Await t.ContinueWhenAll(tasks, Sub()
carePlanSetViewSource.Source = CarePlanList
rcpdSetViewSource.Source = rcpdList
End Sub)
今朝のフィードバックと調査の組み合わせに基づいて、それを行う方法を見つけました。WPFのSTAThreadモデルを考えると、2つのコレクションビューを非同期で構築すること自体はやや非現実的です。ただし、1つのHASが完了していることを確認し、非同期の一部を1つのエンティティクラスからシフトするだけで、これはもっともらしいものになります。
代わりに、基礎となるクラスが独自のAsyncメソッドを使用してデータを構築する最初のタスクを実行します。次に、2番目のコレクションビューを起動する前に、完了したかどうかをテストします。このようにして、コンテキストやディスパッチャオブジェクトについて心配する必要はありません。2番目のコレクションは非同期を使用しません。
Dim personList = Task(Of List(Of person)).Run(Function() personSet.personList)
Dim contactList = Task(Of ObservableCollectionEx(Of contact)).Run(Function() contactSet.contactList)
contactSetViewSource.Source = contactList.Result
If contactList.IsCompleted Then personSetViewSource.Source = personList.Result
これは本当にコンセプト研究のための実験的なプロジェクトです。たまたま、このような2つのリストをこのように作成したいという考えは、それほど有用ではありませんが、データ量の多いインターフェイスを非同期で作成できると便利な場合があります。