How can I tell my DataTemplate to bind to a property in the PARENT ViewModel?

29,187

The answer is this:

<DataTemplate x:Key="CodeGenerationMenuTemplate">
    <MenuItem 
        Header="{Binding Title}" 
        Command="{Binding DataContext.SwitchPageCommand,
    RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}" 
        CommandParameter="{Binding Title}"/>
</DataTemplate>

I just saw that Nir had given me the syntax to solve the above issue on this question: What is the best way in MVVM to build a menu that displays various pages?.

Share:
29,187
Angry Dan
Author by

Angry Dan

web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info

Updated on September 11, 2020

Comments

  • Angry Dan
    Angry Dan over 3 years

    I've got the following MainView.xaml file that works well as a MVVM menu switcher. I've got these pairs:

    • Page1View / Page1ViewModel
    • Page2View / Page2ViewModel

    in my MainViewModel I fill an ObservableCollection with both ViewModels, then when the user clicks the Next button, it calls NextPageCommand in MainViewModel which switches out CurrentPageViewModel with a new ViewModel which is then displayed with an appropriate View, works nicely.

    I also have a Menu being filled with all the titles from the ViewModels in the Observable collection, which also works nicely.

    However, each MenuItem has a Command="{Binding SwitchPageCommand}" which SHOULD call SwitchPageCommand on the MainViewModel and not on e.g. Page1ViewModel or Page2ViewModel.

    So how can I indicate in the template not to bind to the current ViewModel but the ViewModel which contains that ViewModel, e.g. something like this:

    PSEUDO-CODE:
    
    <DataTemplate x:Key="CodeGenerationMenuTemplate">
        <MenuItem 
            Command="{Binding <parentViewModel>.SwitchPageCommand}" 
            Header="{Binding Title}" 
            CommandParameter="{Binding Title}"/>
    </DataTemplate>
    

    Here is MainViewModel:

    <Window x:Class="TestMenu234.Views.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:TestMenu234.Commands"
        xmlns:vm="clr-namespace:TestMenu234.ViewModels"
        xmlns:v="clr-namespace:TestMenu234.Views"
        Title="Main Window" Height="400" Width="800">
    
        <Window.Resources>
            <DataTemplate x:Key="CodeGenerationMenuTemplate">
                <MenuItem Header="{Binding Title}" Command="{Binding SwitchPageCommand}" CommandParameter="{Binding Title}"/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type vm:Page1ViewModel}">
                <v:Page1View/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type vm:Page2ViewModel}">
                <v:Page2View/>
            </DataTemplate>
        </Window.Resources>
    
        <DockPanel>
    
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="Code _Generation" ItemsSource="{Binding AllPageViewModels}"
                          ItemTemplate="{StaticResource CodeGenerationMenuTemplate}"/>
            </Menu>
    
            <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
                <Button Margin="5" Content="Next Page" Command="{Binding NextPageCommand}"/>
            </StackPanel>
    
            <ContentControl
                Content="{Binding CurrentPageViewModel}"/>
    
        </DockPanel>
    </Window>