1

Im trying to learn how to use a contextmenu. I get the menu and it looks good but the commands do not bind in the contextmenu. They do work in the visible button stack panel below the contextmenu. I get this in the output :

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=MainGrid'. BindingExpression:Path=DataContext.StartClientCommand; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')

 <ListBox x:Name="lbSlaves" Grid.Row="1"  
             ItemsSource="{Binding Slaves}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel  />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" Width="150" >
                        <StackPanel Orientation="Horizontal">
                            <CheckBox  IsChecked="{Binding IsSelected ,Mode=TwoWay}"/>
                            <TextBlock Text="{Binding FriendlyName, Mode=OneWay}" >
                                <TextBlock.ContextMenu>
                                    <ContextMenu>
                                        <MenuItem Header="Start" 
                                                  Command="{Binding  ElementName=MainGrid, Path=DataContext.StartClientCommand}" 
                                                  CommandParameter="{Binding}" />
                                        <MenuItem Header="Stop" 
                                                  Command="{Binding  ElementName=MainGrid, Path=DataContext.StopClientCommand}" 
                                                  CommandParameter="{Binding}"  />
                                        <MenuItem Header="Calibrate" 
                                                  Command="{Binding  ElementName=MainGrid, Path=DataContext.CalibrateClientCommand}" 
                                                  CommandParameter="{Binding}" />
                                    </ContextMenu>
                                </TextBlock.ContextMenu>
                            </TextBlock>
                        </StackPanel>
                        <Button 
                        Content="Start"  
                        Command="{Binding  ElementName=MainGrid, Path=DataContext.StartClientCommand}" 
                        CommandParameter="{Binding}" />

                        <Button 
                        Content="Stop"  
                        Command="{Binding  ElementName=MainGrid, Path=DataContext.StopClientCommand}" 
                        CommandParameter="{Binding}" />

                        <Button 
                        Content="Calibrate"  
                        Command="{Binding  ElementName=MainGrid, Path=DataContext.CalibrateClientCommand}" 
                        CommandParameter="{Binding}" />

                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
1

2 Answers 2

3

This is a little tricky. As ContextMenu isn't a part of the visual tree you need to pass the data context in different way. You can do it as followed:

<TextBlock Text="{Binding FriendlyName, Mode=OneWay}" Tag="{Binding Path=DataContext, ElementName=MainGrid}" >
    <TextBlock.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Start" 
                      Command="{Binding Path=PlacementTarget.Tag.StartClientCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                      CommandParameter="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
            <MenuItem Header="Stop" 
                      Command="{Binding  Path=PlacementTarget.Tag.StopClientCommand , RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                      CommandParameter="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}"  />
            <MenuItem Header="Calibrate" 
                      Command="{Binding  Path=PlacementTarget.Tag.CalibrateClientCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                      CommandParameter="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
        </ContextMenu>
    </TextBlock.ContextMenu>
</TextBlock>
Sign up to request clarification or add additional context in comments.

Comments

1

ContextMenu is not part of the Visual Tree, so you can't reach your Grid.

You can get the containing control of ContextMenu using PlacementTarget property.

If you have desgined your ViewModel properly, then your DataContext would reach your CM. In your case, your DataTemplate's DataContext would be enough. If that is not you want, and your Commands are present as static members like the way we have in NavigationCommand class, then you need to assign Command like :

<MenuItem Command="{x:Static local:MyCommands.CustomCommand}" ... />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.