вступление
В MVVM обычная практика состоит в том, чтобы представления находили свои модели представления, разрешая их из контейнера внедрения зависимостей (DI). Это происходит автоматически, когда контейнеру предлагается предоставить (разрешить) экземпляр класса View. Контейнер вводит ViewModel в View, вызывая конструктор View, который принимает параметр ViewModel; эта схема называется инверсией управления (IoC).
Преимущества DI
Основное преимущество здесь заключается в том, что контейнер можно настроить во время выполнения с инструкциями о том, как разрешать типы, которые мы запрашиваем у него. Это обеспечивает большую тестируемость, давая ему указание разрешать типы (представления и модели представления), которые мы используем, когда наше приложение действительно работает, но инструктируя его по-другому при запуске модульных тестов для приложения. В последнем случае у приложения даже не будет пользовательского интерфейса (он не работает; есть только тесты), поэтому контейнер будет разрешать фиктивные типы вместо «нормальных» типов, используемых при запуске приложения.
Проблемы, проистекающие из DI
До сих пор мы видели, что подход DI позволяет легко тестировать приложение, добавляя уровень абстракции над созданием компонентов приложения. У этого подхода есть одна проблема: он плохо работает с визуальными дизайнерами, такими как Microsoft Expression Blend.
Проблема в том, что как при обычном запуске приложения, так и при запуске модульного теста кто-то должен настроить контейнер с инструкциями о том, какие типы разрешать; кроме того, кто-то должен попросить контейнер разрешить представления, чтобы в них можно было внедрить модели представления.
Однако во время разработки нашего кода нет . Дизайнер пытается использовать отражение для создания экземпляров наших представлений, что означает, что:
- Если конструктору View требуется экземпляр ViewModel, дизайнер вообще не сможет создать экземпляр View - он каким-то контролируемым образом выдаст ошибку.
- Если View имеет конструктор без параметров, View будет создан, но так и
DataContext
будет, null
поэтому мы получим «пустое» представление в дизайнере, что не очень полезно.
Введите ViewModelLocator
ViewModelLocator - это дополнительная абстракция, используемая следующим образом:
- Сам View создает экземпляр ViewModelLocator как часть своих ресурсов и привязывает свой DataContext к свойству ViewModel локатора.
- Локатор каким-то образом определяет, находимся ли мы в режиме разработки
- Если не в режиме разработки, локатор возвращает ViewModel, который он разрешает из контейнера DI, как описано выше.
- В режиме разработки локатор возвращает фиксированную «фиктивную» ViewModel, используя свою собственную логику (помните: во время разработки нет контейнера!); эта ViewModel обычно предварительно заполнена фиктивными данными
Конечно, это означает, что View должен иметь конструктор без параметров для начала (иначе дизайнер не сможет создать его экземпляр).
Резюме
ViewModelLocator - это идиома, которая позволяет вам сохранить преимущества DI в вашем приложении MVVM, а также позволяет вашему коду хорошо взаимодействовать с визуальными дизайнерами. Иногда это называется «смешиваемость» вашего приложения (имеется в виду Expression Blend).
После переваривания выше, см практического примера здесь .
Наконец, использование шаблонов данных - это не альтернатива использованию ViewModelLocator, а альтернатива использованию явных пар View / ViewModel для частей вашего пользовательского интерфейса. Часто вы можете обнаружить, что нет необходимости определять View для ViewModel, потому что вместо этого вы можете использовать шаблон данных.
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
. Цель локатора - фактически включить DI в представлениях, потому что WPF плохо его предоставляет. Пример: у вас есть главное окно, которое открывает какое-то диалоговое окно. Чтобы решить DI в диалоговом окне обычным способом, вам нужно будет передать его как зависимость от главного окна! Этого можно избежать с помощью локатора просмотра.Пример реализации ответа @Jon
У меня есть класс локатора модели просмотра. Каждое свойство будет экземпляром модели представления, которую я собираюсь разместить в своем представлении. Я могу проверить, работает ли код в режиме разработки или не используется
DesignerProperties.GetIsInDesignMode
. Это позволяет мне использовать фиктивную модель во время проектирования и реальный объект, когда я запускаю приложение.А чтобы использовать его, я могу добавить свой локатор в
App.xaml
ресурсы:А затем подключить ваше представление (например, MainView.xaml) к вашей модели просмотра:
источник
this
вместоdummy
?Я не понимаю, почему другие ответы на этот вопрос обтекают Дизайнера.
Назначение локатора модели представления - позволить вашему представлению создать экземпляр этого (да, локатор модели представления = сначала просмотр):
вместо этого:
заявив об этом:
Где
ViewModelLocator
класс, который ссылается на IoC и как он решаетMainWindowModel
свойство, которое он предоставляет.Это не имеет ничего общего с предоставлением модели представления для вашего представления. Если хочешь этого, просто сделай
Локатор модели представления - это оболочка для некоторого (любого) контейнера Inversion of Control, такого как, например, Unity.
Ссылаться на:
источник