Что такое ViewModelLocator и каковы его плюсы/минусы по сравнению с DataTemplates?


может ли кто-нибудь дать мне краткое резюме того, что такое ViewModelLocator, как он работает, и какие плюсы/минусы для его использования по сравнению с DataTemplates?

Я попытался найти информацию в Google, но, похоже, есть много разных реализаций этого и нет списка striaght относительно того, что это такое и плюсы/минусы его использования.

3 100

3 ответа:

интро

в MVVM обычная практика заключается в том, чтобы представления находили свои модели просмотра, разрешая их из инъекции зависимостей (DI) контейнер. Это происходит автоматически, когда контейнер просят предоставить (разрешить) экземпляр класса View. Контейнер удалить ViewModel в представление путем вызова конструктора представления, который принимает параметр ViewModel; эта схема называется инверсия управления (МОК.)

преимущества DI

основным преимуществом здесь является то, что контейнер может быть настроен во время с инструкциями о том, как разрешить типы, которые мы запрашиваем от него. Это позволяет повысить тестируемость путем указания ему разрешать типы (представления и модели представлений), которые мы используем при фактическом запуске нашего приложения, но инструктировать его по-другому при запуске модульных тестов для приложения. В последнем случае приложение даже не будет UI (он не работает, только тесты), поэтому контейнер разрешит глумится вместо "обычных" типов, используемых при запуске приложения.

проблемы, вытекающие из DI

до сих пор мы видели, что подход DI позволяет легко тестировать приложение, добавляя слой абстракции над созданием компонентов приложения. Есть одна проблема с этим подходом: он не очень хорошо играет с визуальными дизайнерами таких как Microsoft Expression Blend.

проблема в том, что как в обычных запусках приложений, так и в модульных тестах, кто-то должен настройка контейнер с инструкциями о том, какие типы решения; кроме того, кто-то должен задать контейнер для разрешения представлений, так что ViewModels могут быть введены в них.

, во время разработки нет кода нашего запуска. Дизайнер пытается использовать отражение для создания примеры наших взглядов, что означает:
  • если конструктору представления требуется экземпляр ViewModel, конструктор вообще не сможет создать экземпляр представления - он будет выдавать ошибку некоторым контролируемым образом
  • если представление имеет конструктор без параметров, то представление будет создано, но его DataContext будет null таким образом, мы получим "пустой" вид в конструкторе-что не очень полезно

Enter ViewModelLocator

ViewModelLocator-это дополнительная абстракция, используемая следующим образом:

  • само представление создает экземпляр ViewModelLocator как часть его ресурсы и привязки его DataContext, чтобы свойство модели представления локатора
  • локатор как-то обнаруживает, если мы находимся в режиме конструктора
  • если не в режиме конструктора, локатор возвращает ViewModel, который он разрешает из контейнера DI, как объяснено выше
  • если в режиме конструктора локатор возвращает фиксированную" фиктивную " ViewModel, используя свою собственную логику (помните: во время разработки нет контейнера!); этот ViewModel обычно поставляется с предварительно заполненными фиктивными данными

конечно, это означает, что представление должно иметь конструктор без параметров для начала (в противном случае конструктор не сможет его создать).

резюме

ViewModelLocator это идиома, которая позволяет сохранить преимущества DI в вашем приложении MVVM, а также позволяет вашему коду хорошо играть с визуальными дизайнерами. Иногда это называют "смешиваемость" приложения (имеется в виду смесь выражение).

после переваривания вышеизложенного, смотрите практический пример здесь.

наконец, использование шаблонов данных не является альтернативой использованию ViewModelLocator, но альтернативой использованию явных пар View/ViewModel для частей вашего пользовательского интерфейса. Часто вы можете обнаружить, что нет необходимости определять представление для ViewModel, потому что вместо него можно использовать шаблон данных.

пример реализации @Джон

у меня есть класс модели представления локатор. Каждое свойство будет экземпляром модели представления, которую я собираюсь выделить в своем представлении. Я могу проверить, работает ли код в режиме конструктора или не использует 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) для вашего viewmodel:

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

Я не понимаю, почему другие ответы на этот вопрос обтекать дизайнера.

цель модели представления локатор, чтобы ваш вид, чтобы инстанцировать этого (да, модели представления локатор = вид Первый):

public void MyWindowViewModel(IService someService)
{
}

вместо этого:

public void MyWindowViewModel()
{
}

объявив этот:

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

здесь ViewModelLocator - это класс, который ссылается на МОК, и вот как он решает MainWindowModel свойство, которое он предоставляет.

это не имеет ничего общего с предоставлением макетных моделей просмотра на ваш взгляд. Если вы хотите этого, просто сделайте

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

локатор модели представления-это оболочка вокруг некоторой (любой) инверсии контейнера управления, например Unity.

см.: