3

昨日から続き、新しい複雑さのレイヤーを追加しました。私たちは理論的なModelクラス、ViewModelとViewを持っています。私のモデルはThreading.Timer(「間違った」スレッドのタイマーコールバックを取得するために特別に選ばれました。INotifyPropertyChanged、ObservableCollection、Threads、およびMVVM

をモデルのObservableCollectionを持っている。このタイマコールバック今回はコレクションに項目を追加します。

ViewModelには、単純に渡しますコレクションにバインドされたリストボックスが含まれているビューにコレクション。

これは動作しません。

モデルも同じタイマーコールバックで更新された文字列を公開します。

これもビューモデルを介して公開され、TextBoxにバインドされています。

これは機能します。

私のグーグルで、コレクションの更新によってINotifyCollectionChangedが期待どおりに動作しないというヒントが見られました。私は完全な爆縮を得る。例外でもなく、ただちにアプリケーションを終了させる。

ので、2つの質問があります

一つは、昨日の議論にも関します。ビューが機能するので、私はモデルでINotifyPropertyChangedとObservableCollectionsを使用しています。これらのメカニズムを使用してビューモデルに通知することや、基になるモデルが変更されたことは、今までわかってきました。だから私はどのように別のスレッドで発生した更新を扱うのですか?

第2に、INotifyPropertyChangedがバインディングで動作するのはどういうことでしょうか?文字列プロパティをTextというDependencyPropertyにバインドしています。そのため、DependencyPropertyシステムでUIスレッドに変更をマーシャリングするのですか?編集:そして私はそれに頼ることができますか?すなわち、彼らは私がそれをクロススレッドと話すことを期待しているからですか?それとも、私が頼りにすべきでないキャッチだけですか?

ListBoxはItemsSource = "{Binding ObsCollection}"によってバインドされています。これによりアプリケーションがクラッシュします。実際には、最初に私はそれが実際のVisual Studioを爆撃しまうので、ウィンドウのDataContextのは、設定されたときに起こったモデルが作成されたタイマーを開始しました...

答えて

1

WPFコントロールはスレッド親和性を有する

おかげで、何本そのプロパティがUIスレッドからのみ変更できることを意味します。したがって、Timer(DispatcherTimer以外)からプロパティ値を更新する場合、この更新をUIスレッドにマーシャリングする必要があります。これは、ディスパッチャ経由で施行している:

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Normal, 
    new Action(() => // update your control here)); 

データバインディングフレームワークでは、あなたのモデルは、異なるスレッドからアップデートした場合、これは問題の原因となりますので、更新がUIスレッドにマーシャリングされていることを保証するものではありません。したがって、上記と同じパターンを使用する必要があります。つまり、観測可能なコレクションに異論を追加する場合、この追加はDispatcherを介して実行する必要があります。

+1

これは素晴らしいですが、これをMVVMの観点から処理する「正しい」プロセスは何ですか?私のモデルのスレッドはコレクションを更新しています。私のモデルはDispatcherについて今知っているべきですか?それは間違っているようだ。これは、ViewModelをモデルとビューの間の正確な分離に対処するために重くすることを示唆しています。それは理にかなっていますか? – Ian

+1

「正しい」アプローチはありません。しかし、私の個人的な好みは、ViewModelが依存する単純なインタフェースIMarshalledInvokerを作成することです。IMarshalledInvokerは、他のスレッドでアクションを呼び出すための単一のメソッドを持っています。 ViewModelをビューに結合すると、Dispatcherをカバーの下に使用するIMarshalledInvokerが作成されます。このパターンで、私はまだユニットテストをすることができます、それでもデザイナーのサポートを持つことができます、つまりそれは良いMVVMです;-) – ColinE

+0

ああ、物事は今一緒に来ています。コミックには、私が考慮しなかった方法でお互いに関連する、異種の知識のビットがあります。まず、スレッドセーフなコレクションを作るのは難しいことです。私はそれを忘れて、私の頭の中で協会を作っていなかった...本質的に私は1つのスレッドだけを追加しています。あなたが何をするのか忘れてしまうのは面白いです。答えの要点は、複数のスレッドからの変更を1つのスレッドに振り向けることだと思います。ビューとビューモデルの間には1つのチャンネルがありますか? – Ian

2

この問題は、WPFで非常によく発生しています。私は最良の選択肢は、UIスレッドにイベント通知を自動的にディスパッチする独自のObservableCollection<>サブクラスを持つことだと思います。

車輪は既に発明されているので、私はこの質問の答えにあなたを紹介するつもりです:ObservableCollection and threading

関連する問題