116

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

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

4

3 に答える 3

214

イントロ

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

DIのメリット

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

DIに起因する問題

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

問題は、通常のアプリケーションの実行と単体テストの実行の両方で、誰かが解決するタイプの指示を含むコンテナーをセットアップする必要があることです。さらに、 ViewModelsをビューに挿入できるように、誰かがコンテナにビューを解決するように依頼する必要があります。

ただし、設計時には、実行中のコードはありません。設計者は、リフレクションを使用してビューのインスタンスを作成しようとします。これは、次のことを意味します。

  • ViewコンストラクターがViewModelインスタンスを必要とする場合、デザイナーはViewをまったくインスタンス化できません-何らかの制御された方法でエラーが発生します
  • ビューにパラメーターのないコンストラクターがある場合、ビューはインスタンス化されますが、インスタンス化DataContextされるnullため、デザイナーで「空の」ビューを取得します。これはあまり役に立ちません。

ViewModelLocatorを入力してください

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

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

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

概要

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

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

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

于 2011-03-28T16:49:54.627 に答える
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}}">
于 2015-03-01T02:04:34.600 に答える
8

この質問の他の回答がデザイナーを包み込む理由がわかりません。

ビューモデルロケーターの目的は、ビューがこれをインスタンス化できるようにすることです(はい、ビューモデルロケーター=ビューファースト):

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などの制御の反転コンテナの(任意の)反転のラッパーです。

参照する:

于 2016-12-31T18:40:43.893 に答える