Допустим, я создаю навигационную систему для автомобиля:
- Главное окно будет содержать экран, кнопки режима и регулятор громкости.
- В зависимости отВ режиме системы на экране будет отображаться панель аудио, климат или навигация.
- В режиме аудио будет другой набор кнопок режима и панель, которая может отображать радио, CD илиЭлементы управления MP3.
Моя стратегия для таких соглашений в прошлом состояла в том, чтобы модели моего представления следовали точно такой же иерархии, что и представления.Итак:
- MainViewModel будет иметь ScreenViewModel.
- ScreenViewModel будет иметь AudioViewModel, ClimateViewModel и NavigationViewModel.Он также будет иметь свойство CurrentViewModel, которое будет установлено на модель представления аудио, климата или навигации, в зависимости от режима системы.
- AudioViewModel будет аналогична ScreenViewModel, содержащей модели представления для каждого изрежимы аудиосистемы (радио, CD и MP3), а также свойство для сохранения модели представления для текущего режима.
XAML для привязки представления к модели представления будет выглядеть примерно так:это:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:AudioViewModel}">
<view:AudioPanel />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ClimateViewModel}">
<view:ClimatePanel />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:NavigationViewModel}">
<view:NavigationPanel />
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentViewModel}" />
Если пользователь прослушивает радио и решает ввести пункт назначения в навигационную систему, он нажимает кнопку режима навигации.В MainWindowViewModel будет команда, которая изменяет системный режим на «Navigation» и устанавливает CurrentViewModel в NavigationViewModel.Это приведет к замене NavigationView. Очень чистое решение.
К сожалению, несмотря на то, что такие действия хорошо работают в режиме выполнения, они ломаются при попытке работать с подчиненным представлением (скажем, AudioPanel) в Expression Blend, потому что модель родительского представления (MainWindowViewModel) не существует дляпредоставить AudioViewModel.
Решение, которое, кажется, поддерживается в наборах инструментов, таких как MVVM Light и Simple MVVM, состоит в том, чтобы вместо этого использовать ViewModelLocator, а затем установить представление в свой собственный DataContext путем привязки к правильному свойству локатора.,Затем локатор обслуживает экземпляр модели представления.
«Способ выполнения ViewModelLocator» решает проблему «проектируемости», но мне не ясно, как представлять иерархические отношения и обрабатывать переключение одного представлениядля другого.Концептуально, для меня просто имеет смысл иметь модель представления, содержащую модели дочернего представления.Он правильно представляет иерархию представлений, замена представлений выполняется очень просто, и если представление больше не требуется, связанная модель представления и все ее подчиненные будут подвергаться сборке мусора путем простого удаления ссылки на родительский элемент.
Вопрос
Какова наилучшая практика для создания ViewModelLocator для обработки иерархических представлений, обмена представлениями в зависимости от режима системы и удаления представлений?
В частности:
- Как вы организуете модели представлений, чтобы четко представить иерархические отношения?
- Как вы справляетесь с заменой одного существующего представления на другое (скажем, заменой звуковой панелис панелью навигации)?
- Как обеспечить освобождение моделей родительского и дочернего представлений для сбора мусора, когда связанное родительское представление больше не требуется?