Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way in MVVM to build a menu that displays various pages?

I want to build a simple application with the MVVM pattern.

This application will have two main parts:

  • menu on top
  • content below

The navigation will be simple:

  • each menu item (e.g. "Manage Customers" or "View Reports") will fill the content area with a new page that has some particular functionality

I have done this before with code behind where the code-behind event-handler for menu items had all pages loaded and the one that should be displayed was loaded in as a child of a StackPanel. This, however, will not work in MVVM since you don't want to be manually filling a StackPanel but displaying e.g. a "PageItem" object with a DataTemplate, etc.

So those of you who have made a simple click-menu application like this with MVVM, what was your basic application structure? I'm thinking along these lines:

MainView.xaml:

<DockPanel LastChildFill="False">

    <Menu 
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"/>

    <ContentControl 
        Content="{Binding SelectedPageItem}"/>        

</DockPanel>

where the Menu is filled with a collection of "PageItems" and the DataTemplate displays the Title of each "PageItem object" as the Header of each MenuItem.

And the ContentControl will be filled with a View/ViewModel pair which has full functionality, but am not sure on this.

like image 817
Edward Tanguay Avatar asked Jun 19 '09 15:06

Edward Tanguay


People also ask

Does WPF use MVVM?

MVVM is the lingua franca of WPF developers because it is well suited to the WPF platform, and WPF was designed to make it easy to build applications using the MVVM pattern (amongst others).

Where is Mvvm used?

The Model-View-ViewModel (MVVM) pattern helps to cleanly separate the business and presentation logic of an application from its user interface (UI).


1 Answers

First, I think you should keep the code-behind event handler, there's no point in changing a simple 2 line event handler to a complex command driven monster for no practical reason (and don't say testebility, this is the main menu, it will be tested every time you run the app).

Now, if you do want to go the pure MVVM route, all you have to do it to make your menu fire a command, first, in some resource section add this style:

<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>

This style will make the menu item fire a the SwitchViewCommand on the attached view model with the MenuItem's DataContext as the command parameter.

The actual view is the same as your code with an additional reference to that style as the ItemContainerStyle (so it applies to the menu item and not the content of the DataTemplate):

<DockPanel LastChildFill="False">

    <Menu DockPanel.Dock="Top"
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"
        ItemContainerStyle="{StaticResource MenuItemStyle}"/>
    <ContentControl 
    Content="{Binding SelectedPageItem}"/>
</DockPanel>

Now in the view model you need (I used strings because I don't have your PageItem code):

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; }

And use whatever command class you use to make the command call this code:

private void DoSwitchViewCommand(object parameter)
{
    SelectedPageItem = (string)parameter;
}

Now, when the user clicks a menu item the menu item will call the SwitchViewCommand with the page item as the parameter.

The command will call the DoSwitchViewCommand that will set the SelectedPageItem property

The property will raise the NotifyPropertyChanged that will make the UI update via data binding.

Or, you can write a 2 line event handler, your choice

like image 146
Nir Avatar answered Oct 31 '22 02:10

Nir