Search code examples
wpfbindingcommandcontentcontrolcommandparameter

Different Datacontext for Command and CommandParameter


Is it possible to have a different Datacontext for a WPF Command and a CommandParameter?

<UserControl>
<UserControl.Resources>
    <viewmodels:ListViewGridBaseViewModel x:Key="vm" />
</UserControl.Resources>
<Grid>
    <ContentControl x:Name="currentContent" 
                    Content="{Binding Path=ListGrid}" >
        <ContentControl.ContextMenu>
            <ContextMenu >
                <MenuItem Command="{Binding Path=Save}" 
                          CommandParameter="{Binding ElementName=currentContent}"
                          DataContext="{StaticResource ResourceKey=vm}"
                          Header="Save">
                    <MenuItem.Icon>
                        <Image Source="{StaticResource ResourceKey=Save}"
                               Height="16"
                               Width="16"/>
                    </MenuItem.Icon>
                </MenuItem>
                <MenuItem Command="{Binding Path=Revert}" 
                          DataContext="{StaticResource ResourceKey=vm}"
                          Header="Revert">
                    <MenuItem.Icon>
                        <Image Source="{StaticResource ResourceKey=Revert}"
                               Height="16"
                               Width="16"/>
                    </MenuItem.Icon>
                </MenuItem>
            </ContextMenu>
        </ContentControl.ContextMenu>
    </ContentControl>
</Grid>
</UserControl>

I want the Binding for ListGrid bubbled up to another Viewmodel and the Command to a local ViewModel. But the CommandParameter should be the ContentControl. LOG is saying:

System.Windows.Data Error: 4 : Cannot find source for binding with 
reference 'ElementName=currentContent'. BindingExpression:(no path); 
DataItem=null; target element is 'MenuItem' (Name=''); 
target property is 'CommandParameter' (type 'Object')

Solution

  • ContextMenu breaks the DataContext inheritance chain, that's why ElementName=currentContent cannot be found.

    Look here for artificial inheritance context and use the class DataContextSpy

    then do the following:

    <UserControl>
    <UserControl.Resources>
        <viewmodels:ListViewGridBaseViewModel x:Key="vm" />
        <local:DataContextSpy DataContext="{Binding ElementName=currentContent}" x:Key="Spy">
    </UserControl.Resources>
    <Grid>
        <ContentControl x:Name="currentContent" 
                        Content="{Binding Path=ListGrid}" >
            <ContentControl.ContextMenu>
                <ContextMenu >
                    <MenuItem Command="{Binding Path=Save}" 
                              CommandParameter="{Binding DataContext,Source={StaticResource Spy}}"
                              DataContext="{StaticResource ResourceKey=vm}"
                              Header="Save">
                        <MenuItem.Icon>
                            <Image Source="{StaticResource ResourceKey=Save}"
                                   Height="16"
                                   Width="16"/>
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem Command="{Binding Path=Revert}" 
                              DataContext="{StaticResource ResourceKey=vm}"
                              Header="Revert">
                        <MenuItem.Icon>
                            <Image Source="{StaticResource ResourceKey=Revert}"
                                   Height="16"
                                   Width="16"/>
                        </MenuItem.Icon>
                    </MenuItem>
                </ContextMenu>
            </ContentControl.ContextMenu>
        </ContentControl>
    </Grid>
    </UserControl>