2012-02-14 11 views
5

私のWPFアプリケーションでは、MVVMパターンを依存性インジェクションとともに使用します。依存関係インジェクションを使用したMVVM ViewModelsの古いデータ

データベースからデータを準備するViewModelsは、コンストラクタに注入されたリポジトリを取得します。また、コンストラクタ内のリポジトリからのデータをプロパティに取り込みます。

ViewModelはすべて、ViewModelLocatorクラスの静的コンストラクターで作成され、すべてのビューがViewModelにバインドするために使用されます。

これは、次のような欠点がありますViewModelにインスタンスが常に同じであるため、ビューで

  1. データは、それらを閉じて再開いていない場合でも、更新されることはありません。
  2. 最初のビューを開くと、すべてのViewModelがインスタンス化され、必要なデータがデータベースからロードされます。私はこれらの問題を解決するには、2つの方法を考えることができ

: - ではなく、コンストラクタでそうするの

  1. は、すべてのViewModelには、データベースからデータを読み込み、プロパティを初期化するメソッドを実装してください。これは、ビューが開かれるたびにそのメソッドを呼び出す必要があります。これは私が好きではないtemporal couplingを紹介します。
  2. ViewModelLocatorの対応するプロパティが呼び出されるたびに、要求されたViewModelを作成するように、ViewModelLocatorを実装します。私はこの方法が嫌いです。なぜなら、私のコンポジションルートはプログラムの開始時には実行されず、プログラムインスタンスのライフタイム全体に広がるからです。

この問題を解決する別の方法はありますか?どのように他の人はこれを解決していますか?

答えて

2

は、要求のViewModelにViewModelLocator上の対応するプロパティが呼び出されるたびに作成されますようにViewModelLocatorを実装(私は簡単にするためINPCの通知を残しています)。

これは私が通常このような状況で取るアプローチのほうが多いです。しかし、ViewModelのDI経由でViewModelLocatorを作成するのではなく、ViewModelを作成するファクトリを作成します。

私のコンポジションルートはプログラムの起動時には実行されないが、プログラムインスタンスのライフタイム全体に広がるため、この方法は嫌いです。

これは、少なくとも部分的に、構成自体がタイプ自体ではなく工場を構成することによって「解決」される。コンポジションは起動時に1回発生しますが、問題のViewModelのいつでも作成が可能です。

たとえば、MEFを使用すると、インポートタイプを直接入力する代わりにExportFactory<T>に切り替えることができます。 NonShared Creation Policyと一緒に、必要に応じてViewModelsを構築し、一時的な結合の問題なしに常に新しいデータを扱うことができます。

+0

あなたの答えをありがとう。私のViewModelごとに工場を持つことは、工場が1か所でしか使用されず、現時点では必要ではないため、少し残忍なようです。さらに、彼らは 'container.Resolve'よりも何もしません。 ViewModelLocatorはコンテナが使用される唯一の場所であるため、抽象ファクトリを介して 'container.Resolve'を呼び出すことをお勧めします。この場合でもコンテナはアプリケーションコードに漏れないためです。私が考えることができる抽象的な工場の唯一の利点は、コンテナの構成が正しくない場合、起動時にすぐにエラーが発生することです(続き)。 –

+0

(続き)。 –

0

私の抽象的なViewModelBaseでは、抽象的なRefreshDataCore()メソッドが必要です。このメソッドは、ViewModelインスタンスでRefresh()を呼び出すか、IsDirtyフラグを設定して手動で呼び出すことができます。 ViewModel.IsVisibleがtrueでIsDirtyが設定されている場合、Refresh()も呼び出されます。

このようにして、ビューモデルが表示されるたびにデータのリフレッシュを行うことができます。リフレッシュ()を呼び出すと、手動でリフレッシュを呼び出すこともできます。

以下の例。

public abstract class ViewModelBase 
{ 
    //Pull your data from the repository here 
    protected abstract void RefreshCore(); 
    public void Refresh() 
    { 
      RefreshCore(); 
      IsDirty = false; 
    } 

    private bool _isVisible = false; 
    //DataBind this to the visibility of element "hosting" your view model 
    public bool IsVisible 
    { 
     get { return _isVisible; } 
     set 
     { 
       if (_isVisible == value) 
        return; 


       _isVisible = value; 
       if (IsVisible && IsDirty) 
        Refresh(); 
     } 
    } 

    private bool _isDirty = true; 
    public bool IsDirty 
    { 
     get { return _isDirty; } 
     set 
     { 
      if (_isDirty == value) 
       return; 

      _isDirty = value; 
      if (IsVisible && IsDirty) 
       Refresh(); 
     } 
    } 

} 
+1

時間的結合問題をどのように解決しますか?あなたはそれだけで生活し、必要に応じていつもリフレッシュを呼びますか? –

+0

私は、データの状態を定期的にチェックし、適切なIsDirtyフラグを設定するApplicationViewModelを持っています(ただし、可視モデルのみがアクティブにリフレッシュされます)。 パフォーマンス上の理由から、ApplicationViewModelには、他のViewModelBaseインスタンスそれらのRefreshDataCore()メソッドから読み込みます。必要に応じてこれを実装する完全な柔軟性があります。 – cordialgerm

+0

あなたの答えをありがとう。しかし、私は一時的なカップリングが解決されていないと思うので、それは私が使用しようとしているものではありません。 –

関連する問題