Каков наилучший способ в MVVM создать меню, отображающее различные страницы?
Я хочу создать простое приложение с шаблоном MVVM.
Это приложение будет иметь две основные части:
- меню сверху
- контент ниже
навигация будет простой:
- каждого пункт меню (например, "управление клиентами" или "просмотр отчетов") будет заполните область содержимого С новой страницы, имеет некоторые особенности функциональность
Я делал это раньше с кодом где обработчик событий кода для пунктов меню загрузил все страницы, а та, которая должна отображаться, была загружена в качестве дочернего элемента StackPanel. Это, однако, не будет работать в MVVM, так как вы не хотите вручную заполнять StackPanel, но отображать, например, объект "PageItem" с DataTemplate и т. д.
Итак, те из вас, кто сделал простое приложение клик-меню как это с MVVM, какова была ваша основная структура приложения? Я думаю примерно так:
представлении MainView.язык XAML:
<DockPanel LastChildFill="False">
<Menu
ItemsSource="{Binding PageItemsMainMenu}"
ItemTemplate="{StaticResource MainMenuStyle}"/>
<ContentControl
Content="{Binding SelectedPageItem}"/>
</DockPanel>
где меню заполнено коллекцией "PageItems", а DataTemplate отображает заголовок каждого" объекта PageItem " в качестве заголовка каждого MenuItem.
и ContentControl будет заполнен парой View/ViewModel, которая имеет полную функциональность, но я не уверен в этом.
3 ответов
во-первых, я думаю, что вы должны сохранить обработчик событий кода, нет смысла менять простой обработчик событий 2 строки на сложный управляемый командой монстр без какой-либо практической причины (и не говорите testebility, это главное меню, оно будет проверяться каждый раз, когда вы запускаете приложение).
теперь, если вы хотите пройти чистый маршрут MVVM, все, что вам нужно сделать, чтобы ваше меню выстрелило командой, сначала в каком-то разделе ресурсов добавьте этот стиль:
<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding DataContext.SwitchViewCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/>
<Setter Property="CommandParameter"
Value="{Binding}"/>
</Style>
этот стиль заставит пункт меню запустить SwitchViewCommand на прикрепленной модели представления с DataContext MenuItem в качестве параметра команды.
фактическое представление совпадает с вашим кодом с дополнительной ссылкой на этот стиль как ItemContainerStyle (поэтому он применяется к пункту меню, а не к содержимому DataTemplate):
<DockPanel LastChildFill="False">
<Menu DockPanel.Dock="Top"
ItemsSource="{Binding PageItemsMainMenu}"
ItemTemplate="{StaticResource MainMenuStyle}"
ItemContainerStyle="{StaticResource MenuItemStyle}"/>
<ContentControl
Content="{Binding SelectedPageItem}"/>
</DockPanel>
теперь в модели представления вам нужно (я использовал строки, потому что у меня нет кода PageItem):
private string _selectedViewItem;
public List<string> PageItemsMainMenu { get; set; }
public string SelectedPageItem
{
get { return _selectedViewItem; }
set { _selectedViewItem = value; OnNotifyPropertyChanged("SelectedPageItem"); }
}
public ICommand SwitchViewCommand { get; set; }
и использовать все, что угодно класс команд, который вы используете для вызова команды этот код:
private void DoSwitchViewCommand(object parameter)
{
SelectedPageItem = (string)parameter;
}
теперь, когда пользователь щелкает элемент меню, элемент меню вызовет SwitchViewCommand с элементом страницы в качестве параметра.
команда вызовет DoSwitchViewCommand, который установит свойство SelectedPageItem
свойство вызовет NotifyPropertyChanged, который сделает обновление пользовательского интерфейса через привязку данных.
или, вы можете написать обработчик события 2 строк, ваш выбор
Я мог представить себе ObservableCollection в VM, который содержит все страницы, которые можно вызвать из меню. Затем привяжите к нему ItemsControl и ContentControl, чтобы ContentControl всегда показывал CurrentItem из этого списка. Конечно, меню будет привязываться только к некоторому свойству Title в то время как ContentControl примет весь элемент и подключит некоторое соответствующее представление в соответствии с типом.
другой вариант-использовать список вместо меню, Стиль списка, чтобы выглядеть как меню, а затем вы можете привязать к выбранному значению, например:
<DockPanel LastChildFill="False">
<ListBox
ItemsSource="{Binding PageItemsMainMenu}"
ItemTemplate="{StaticResource MainMenuStyle}"
IsSynchronizedWithCurrentItem="True"/>
<ContentControl
Content="{Binding PageItemsMainMenu/}"/>
</DockPanel>
обратите внимание на IsSynchronizedWithCurrentItem= "True" для установки выбранного элемента и {Binding PageItemsMainMenu/} с конечной косой чертой для его использования.