0

I have a DataGird, then it's include Expander and ContextMenu.

This DataGird is grouping. And, it's has different ContextMenu between Expander and DataGridItem.

However, I want to binding MenuItem Command to my command, and pass DataGird's SelectedItems or SelectedIndex to Command.

But this command is not invoked. Even if it work, the parameter is not pass when I survey some method got goal (like set property tag).

So, I want to know what's correct method.

General

<UserControl.DataContext>
    <vm:ViewModel x:Name="VM"/>
</UserControl.DataContext>
<Grid>
    <DataGrid x:Name="dg"
              ItemsSource="{Binding SourceData}"
              AutoGenerateColumns="False" 
              CanUserResizeColumns="False" 
              CanUserResizeRows="False"
              CanUserAddRows="False" 
              CanUserSortColumns="False"
              SelectionMode="Extended"
              RowHeaderWidth="0"
              GridLinesVisibility="Horizontal">
        <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                <Setter Property="BorderThickness" Value="0"/>
                <!-- Remove the focus indication for the selected cell -->
                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            </Style>
        </DataGrid.CellStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header="No." Binding="{Binding No}" />
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
        </DataGrid.Columns>
        <DataGrid.GroupStyle>
            <GroupStyle>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate>
                                    <Expander IsExpanded="False"  MouseRightButtonDown="Expander_MouseRightButtonDown" ButtonBase.Click="Expander_Click">
                                        <Expander.Header>
                                            <StackPanel Orientation="Horizontal">
                                                <StackPanel.ContextMenu>
                                                    <ContextMenu>
                                                        <MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding InsertGroupItems"/>
                                                        <MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding RemoveGroupItems"/>
                                                    </ContextMenu>
                                                </StackPanel.ContextMenu>
                                                <TextBlock Text="{Binding Name}"/>
                                                <TextBlock Text="{Binding ItemCount}"/>
                                                <TextBlock Text=" item(s)"/>
                                            </StackPanel>
                                        </Expander.Header>
                                        <ItemsPresenter>
                                            <ItemsPresenter.ContextMenu>
                                                <ContextMenu>
                                                    <ContextMenu>
                                                        <MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding InsertSelectedItems" CommandParameter="{Binding ElementName=dg, Path=SelectedIndex}"/>
                                                        <MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding RemoveSelectedItems" CommandParameter="{Binding ElementName=dg, Path=SelectedItems}"/>
                                                    </ContextMenu>
                                            </ItemsPresenter.ContextMenu>
                                        </ItemsPresenter>
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </DataGrid.GroupStyle>
    </DataGrid>
</Grid>

This work to invoke command, but can't pass parameter

<DataGrid.GroupStyle>
            <GroupStyle>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                            <Setter Property="ContextMenu">
                                <Setter.Value>
                                    <ContextMenu>
                                        <MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding PlacementTarget.Tag.InsertSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}" CommandParameter="{Binding ElementName=dg, Path=SelectedIndex}"/>
                                        <MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding PlacementTarget.Tag.RemoveSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}" CommandParameter="{Binding ElementName=dg, Path=SelectedItems}"/>
                                    </ContextMenu>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <Expander IsExpanded="False"  MouseRightButtonDown="Expander_MouseRightButtonDown" ButtonBase.Click="Expander_Click">
                                            <Expander.Header>
                                                <StackPanel Orientation="Horizontal">
                                                    <StackPanel.ContextMenu>
                                                        <ContextMenu>
                                                            <MenuItem Header="Insert" InputGestureText="Ctrl+I" Command="{Binding InsertGroupItems}"/>
                                                            <MenuItem Header="Remove" InputGestureText="Ctrl+D" Command="{Binding RemoveGroupItems}"/>
                                                        </ContextMenu>
                                                    </StackPanel.ContextMenu>
                                                    <TextBlock Text="{Binding Name}"/>
                                                    <TextBlock Text="{Binding ItemCount}"/>
                                                    <TextBlock Text=" item(s)"/>
                                                </StackPanel>
                                            </Expander.Header>
                                            <ItemsPresenter/>
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </DataGrid.GroupStyle>

BTW, how to cast SelectedItems when got parameter?

It's not work

private void Excute(object parameter)
{
    IList list = parameter as IList;
    foreach (var item in list)
    {
        Remove((Data)item);
    }
}

So, maybe I have three problems.

  1. The ContextMenu not working.

  2. The CommandParameter not passing.

  3. How to convert SelectedItems to a list?

Thanks!

1 Answer 1

2

A MenuItem in a ContextMenu can't use an ElementName to bind to the DataGrid because the ContextMenu and the DataGrid belong to different element trees.

What you could do is to bind the Tag property of the ItemsPresenter to the DataGrid and then bind to properties of the DataGrid through the PlacementTarget of the ContextMenu:

<ItemsPresenter Tag="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}}">
    <ItemsPresenter.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Insert2" InputGestureText="Ctrl+I"
                        DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                        Command="{Binding DataContext.InsertSelectedItems}"
                        CommandParameter="{Binding SelectedIndex}"/>
            <MenuItem Header="Remove2" InputGestureText="Ctrl+D"
                        DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                        Command="{Binding DataContext.RemoveSelectedItems}"
                        CommandParameter="{Binding SelectedItems}"/>
        </ContextMenu>
    </ItemsPresenter.ContextMenu>
</ItemsPresenter>

How to convert SelectedItems to a list?

Like you are doing. This should work provided that the binding to the SelectedItems property of the DataGrid works:

private void Execute(object parameter)
{
    IList list = parameter as IList;
    foreach (var item in list)
    {
        Remove((Data)item);
    }
}

Edit:

Of course you cannot use ElementName when binding to the CommandArgument either. Try this:

<Style TargetType="{x:Type GroupItem}">
    <Setter Property="Tag" Value="{Binding Path=., RelativeSource={RelativeSource AncestorType=DataGrid}}" />
    <Setter Property="ContextMenu">
        <Setter.Value>
            <ContextMenu>
                <MenuItem Header="Insert" InputGestureText="Ctrl+I"
                          Command="{Binding PlacementTarget.Tag.DataContext.InsertSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                          CommandParameter="{Binding PlacementTarget.Tag.SelectedIndex, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
                <MenuItem Header="Remove" InputGestureText="Ctrl+D"
                          Command="{Binding PlacementTarget.Tag.DataContext.RemoveSelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
                          CommandParameter="{Binding PlacementTarget.Tag.SelectedItems, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
            </ContextMenu>
        </Setter.Value>
    </Setter>
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks your answer. I try your code is not work, If I define Tag and ContextMenu by style in <GroupStyle.ContainerStyle>. This is confused. I will update my code.
It surely works for me. I don't know what "this is confused" means.
Sorry, I don't understand you. Maybe you should read my answer once more.
Of course you cannot use ElementName when binding to the CommandArgument either.
Oh.. Maybe you can see my update code. I will try again use a empty project.
|

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.