2011-06-30 6 views
5

私のViewModel外のクラスからスレッドを処理する方法を理解しています。MVVMビューモデルでC#WPFスレッドを処理する方法

スレッドはTrackクラスに由来します。ここでResponseEventHandlerコードがTrackである:「コマンド」メソッドは、私のTrackオブジェクト内から処理されると

public delegate void ResponseEventHandler(AbstractResponse response); 
public event ResponseEventHandler OnResponseEvent; 

、次のコードは、戻って私のViewModelにスレッドにメッセージを送信OnResponseEventを実行します:

if (OnResponseEvent != null) 
{ 
    OnResponseEvent(GetResponseFromCurrentBuffer()); 
} 

GetResponseFromCurrentBuffer()は、Track内の事前定義タイプのメッセージタイプを返します。

MainWindowViewModelコンストラクタはTrackからOnResponseEventのイベントハンドラを作成します。

public MainWindowViewModel() 
{ 
    Track _Track = new Track(); 

    _Track.OnResponseEvent += 
     new Track.ResponseEventHandler(UpdateTrackResponseWindow); 
} 

だから、アイデアは私がOnResponseEventスレッドからの新しいメッセージを持っているたびに、私はUpdateTrackResponseWindow()メソッドを実行することです。このメソッドは、TrackResponseMessageと呼ばObservableCollection<string>リストプロパティに新しいメッセージ文字列を追加します:

private void UpdateTrackResponseWindow(AbstractResponse message) 
{ 
    TrackResponseMessage.Add(FormatMessageResponseToString(message)); 
} 

FormatMessageResponseToString()方法は、単にTrack内のすべての事前定義されたメッセージタイプとメッセージを比較して、いくつかの気の利いた文字列フォーマットを行います。

主な問題は次のとおりです。TrackResponseMessage.Add()を実行するとUIが消えます。実行可能ファイルは、まだバックグラウンドで実行し、タスクを終了する唯一の方法は、Visual Studio 2010

TrackResponseMessageをシャットダウンするのは、私のViewModel内のパブリックプロパティです:

public ObservableCollection<String> TrackResponseMessage 
{ 
    get { return _trackResponseMessage; } 
    set 
    { 
     _trackResponseMessage = value; 
     RaisePropertyChanged("TrackResponseMessage"); 
    } 
} 

がが必要ですTrackオブジェクトから来たThreadを私のViewModelにマーシャリングするには?どのようなサンプルコードも非常に高く評価されます!

答えて

9

Track.csオブジェクトからのスレッドを私のビューモデルにマーシャリングする必要がありますか?どのようなサンプルコードも非常に高く評価されます!

はい。残念ながら、INotifyPropertyChangedは他のスレッドからのイベントを処理しますが、INotifyCollectionChangedは処理しません(つまり:ObservableCollection<T>)。そのため、VMにマーシャリングする必要があります。

VMがビュー(View-First MVVM)から作成されているか、またはUIスレッドで作成されていることがわかっているVMを使用すると良い選択肢があります。その後

TaskScheduler uiScheduler; 
public MainWindowViewModel() 
{ 
    uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
    Track _Track = new Track(); 
    _Track.OnResponseEvent += new Track.ResponseEventHandler(UpdateTrackResponseWindow); 
} 

、後で、あなたのイベントハンドラを行うことができます:NET 4つのタスクを

private void UpdateTrackResponseWindow(AbstractResponse message) 
{ 
    Task.Factory.StartNew(
     () => TrackResponseMessage.Add(FormatMessageResponseToString(message)), 
     CancellationToken.None, TaskCreationOptions.None, 
     uiScheduler); 
} 

これはつまり、(あなたのViewModelクラスにWPFやSilverlightの特定のリソースと種類を引っ張っていないの素敵な利点があります: Dispatcher)、それでもすべての利点を提供します。また、スレッドアフィニティ(すなわち:WCFサービス作業)を持つ他のルーチンでも、変更されません。

+0

Yeeehaw !!それは素晴らしかった!リード、私はあなたにドーナツを借りています! .netスレッドのドキュメントを読む時間を節約できました。 TaskSchedulerを使用すると、ビューモデル内の他のクラスオブジェクトからのスレッドの読み込みが容易になります。 – EnLaCucha

+0

@EnLaCucha:FYI - これは、SynchronizationContextがインストールされているスレッドでのみ機能します。これは、WPFのメインスレッド、WinFormsのメインスレッド、WCFサービスコールにも当てはまります。 –

+0

.net 4.5では、BindingOperations.EnableCollectionSynchronizationを使用して別のスレッドからコレクションを編集できるようになりました。https://msdn.microsoft.com/en-us/library/hh140164(v=vs.110).aspx – Kelly

0

UIスレッド以外のスレッドでRaisePropertychangedが実行され、イベントのイベントハンドラがUIに触れる場合は、UIスレッドに切り替える必要があります。

関連する問題