ViewModelLocatorとは何ですか?DataTemplatesと比較してその長所/短所は何ですか?


112

誰かがViewModelLocatorとは何か、それがどのように機能するか、DataTemplatesと比較してそれを使用する場合の長所/短所は何かについて簡単な要約を教えてもらえますか?

私はグーグルで情報を見つけようとしましたが、それの多くの異なる実装があり、それが何であるか、それを使用することの賛否両論についての重要なリストはないようです。

回答:


204

はじめに

MVVMでは、通常、依存関係注入(DI)コンテナーからビューを解決することにより、ビューがビューモデルを見つけるようにします。これは、コンテナーがViewクラスのインスタンスを提供(解決)するように要求されたときに自動的に発生します。コンテナは、ViewModelパラメータを受け入れるViewのコンストラクタを呼び出すことにより、ViewModelをViewに注入します。このスキームは、制御の反転(IoC)と呼ばれます

DIの利点

ここでの主な利点は、リクエストしたタイプを解決する方法の指示により、実行時にコンテナーを構成できることです。これにより、アプリケーションの実際の実行時に使用するタイプ(ビューとビューモデル)を解決するように指示し、アプリケーションの単体テストを実行するときに異なる方法で指示することで、テスト容易性を高めることができます。後者の場合、アプリケーションにはUIさえありません(実行されていません。テストのみです)。そのため、コンテナーは、アプリケーションの実行時に使用される「通常の」タイプの代わりにモックを解決ます。

DIに起因する問題

これまでのところ、DIアプローチでは、アプリケーションコンポーネントの作成に抽象化レイヤーを追加することで、アプリケーションのテスト容易性が実現されることを確認しました。このアプローチには1つの問題があります。MicrosoftExpression Blendなどのビジュアルデザイナーではうまく機能しません

問題は、通常のアプリケーションの実行と単体テストの実行の両方で、解決するタイプの指示を誰かがコンテナに設定する必要があることです。さらに、誰かがしなければならない頼むのviewmodelsがそれらに注入することができるように、ビューを解決するための容器を。

ただし、デザインタイムには実行中のコードはありません。デザイナーは、リフレクションを使用してビューのインスタンスを作成しようとします。つまり、

  • ViewコンストラクターがViewModelインスタンスを必要とする場合、デザイナーはViewをインスタンス化できません-制御された方法でエラーになります
  • Viewはパラメータなしのコンストラクタを持っている場合はビューがインスタンス化されますが、そのはDataContextになりますnull私たちは「デザイナーの『空』ビューちゃうので-非常に便利ではありません

ViewModelLocatorを入力してください

ViewModelLocatorは、次のように使用される追加の抽象化です。

  • ビュー自体がリソースの一部としてViewModelLocatorをインスタンス化し、そのDataContextをロケーターのViewModelプロパティにデータバインドします。
  • ロケーターは、デザインモードかどうかを何らかの方法で検出します
  • 上記で説明したように、デザインモードでない場合、ロケーターはDIコンテナーから解決するViewModelを返します。
  • デザインモードの場合、ロケーターは独自のロジックを使用して、固定された「ダミー」のViewModelを返します(デザインタイムにはコンテナーがないことに注意してください)。このViewModelは通常、ダミーデータが事前に入力されています

もちろんこれは、ビューには最初にパラメーターのないコンストラクターが必要であることを意味します(そうしないと、デザイナーはインスタンス化できません)。

概要

ViewModelLocatorは、MVVMアプリケーションでDIの利点を維持しながら、コードをビジュアルデザイナーとうまく連携させることができるイディオムです。これは、アプリケーションの「ブレンド可能性」と呼ばれることもあります(Expression Blendを指します)。

上記を消化した後、実際の例を参照してくださいここに

最後に、データテンプレートの使用は、ViewModelLocatorの使用に代わるものではなく、UIの一部に明示的なView / ViewModelペアを使用することに代わるものです。代わりにデータテンプレートを使用できるため、ViewModelのビューを定義する必要がないことがよくあります。


4
素晴らしい説明のための+1。ビューとそのリソースをさらに拡張できますか?リソースとは、ビューのプロパティを意味しますか?それとも?このパターンへの具体的な例とのリンクはありますか?
Metro Smurf

@MetroSmurf:リンクは[概要]セクションにあります。
Jon

1
ありがとう。ViewModelLocatorの使用に制限はありますか?静的リソースを参照するという事実についていくつかの懸念がありました-実行時にViewModelを動的に作成できますか?そして、それをフックすることを含む多くの余分なコードがありますか?
レイチェル

@Rachel:概要の同じリンクは、実用的な例でこれらの質問に答えるべきです。
Jon

2
非常に誤解を招く答え。View Model Locatorの主な目的は、設計者にダミーデータを提供することではありません。これは、を指定することで簡単に実行できますd:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"。ロケーターの目的は、WPFがDIを提供するのが非常に悪いため、ビューでDIを実際に有効にすることです。例:ダイアログウィンドウを開くメインウィンドウがあります。通常の方法でダイアログウィンドウのDIを解決するには、メインウィンドウへの依存関係としてそれを渡す必要があります!これは、ビューロケータで回避されます。
hyankov 2016

10

@Jonの回答の実装例

ビューモデルロケータークラスがあります。各プロパティは、ビューに割り当てるビューモデルのインスタンスになります。コードがデザインモードで実行されているかどうかを確認できますDesignerProperties.GetIsInDesignMode。これにより、設計時にモックモデルを使用し、アプリケーションを実行しているときに実際のオブジェクトを使用できます。

public class ViewModelLocator
{
    private DependencyObject dummy = new DependencyObject();

    public IMainViewModel MainViewModel
    {
        get
        {
            if (IsInDesignMode())
            {
                return new MockMainViewModel();
            }

            return MyIoC.Container.GetExportedValue<IMainViewModel>();
        }
    }

    // returns true if editing .xaml file in VS for example
    private bool IsInDesignMode()
    {
        return DesignerProperties.GetIsInDesignMode(dummy);
    }
}

そして、それを使用するために、ロケーターをApp.xamlリソースに追加できます。

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>

次に、ビュー(例:MainView.xaml)をビューモデルに接続します。

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">

this代わりにを使用することに違いはありますdummyか?
Sebastian XaweryWiśniowiecki

5

この質問の他の回答がなぜデザイナーを取り巻くのか理解できません。

ビューモデルロケーターの目的は、ビューでこれをインスタンス化できるようにすることです(はい、ビューモデルロケーター=最初に表示)。

public void MyWindowViewModel(IService someService)
{
}

これだけではなく:

public void MyWindowViewModel()
{
}

これを宣言することによって:

DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"

ViewModelLocatorIoCを参照するクラスはどこにあり、それはMainWindowModelそれが公開するプロパティを解決する方法です。

モックビューモデルをビューに提供することとは関係ありません。それが必要な場合は、

d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"

View Model Locatorは、Unityなどの一部の(任意の)Inversion of Controlコンテナーのラッパーです。

参照する:


ビューモデルロケーターはコンテナーを必要としません。ユーザーはビューモデルが構成を介してどのように解決されるかを決定し、コンテナーを使用するか、自分でタイプを新規作成できます。したがって、たとえば、コンテナにすべてのビューとビューモデルを事前登録する代わりに、コンベンションベースのビューモデルの場所を実行できます。
クリスボーデマン2017

他の回答がなぜデザイナーをラップするのか理解できない[ +1 ] +1ですが、ロケーターのポイントは、ビューモデルがどのようになっているかについての知識をビューから削除することです。作成し、ビューをこのインスタンス化から独立させ、ロケーターに任せます。ロケーターは、ビューモデルのさまざまなフレーバーを提供できるようになります。おそらく、ロケーターが管理するプラグインを介して追加されたいくつかのカスタムフレーバー(および設計時の特定のフレーバー)を提供します。ビューは、ビューモデルの正しいバージョンを特定するこのプロセスのいずれかを排除します。これは、確かにSoCに適しています。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.