ContextMenu for ListViewItem only
Asked Answered
F

2

12

I have a context menu - problem is I need it to only open when a listviewitem is clicked. Right now it will open if I click anywhere in the listview or in the header.

<ListView> 
    <ListView.ContextMenu>
        <ContextMenu>
            <MenuItem Header="More Info" Command="{Binding MoreInfo}" />
        </ContextMenu>
     </ListView.ContextMenu>
     <ListView.View> 
         <GridView> 
           <!-- columns and stuff here -->
         </GridView>
     </ListView.View>
 </ListView>

I have tried adding the ContextMenu as a resource and applying it as a style, but this breaks the command (clicking on More Info should open a dialog window, doesnt work this way)

<ListView.Resources>
    <ContextMenu x:Key="ItemContextMenu">
        <MenuItem Header="More Info" Command="{Binding MoreInfo}" Background="WhiteSmoke" />
    </ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}" >
        <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
    </Style>
</ListView.ItemContainerStyle>

So not sure how to restrict the context menu to only the listviewitem and have the command work.

Florez answered 20/9, 2013 at 16:7 Comment(0)
D
34

Use the RelativeSource in the command binding in the template, and it will work:

<ListView.Resources>
    <ContextMenu x:Key="ItemContextMenu">
        <MenuItem Header="More Info" Command="{Binding Path=DataContext.MoreInfo, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" Background="WhiteSmoke" />
    </ContextMenu>
</ListView.Resources>

<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}" >
        <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
    </Style>
</ListView.ItemContainerStyle>
Dragonfly answered 20/9, 2013 at 16:22 Comment(2)
Thanks, this worked. Any change you could explain exactly what this is doing? I'm a little fuzzy on what FindAncestor does.Florez
In your case, the RelativeSource trying to find the first ListView control in UI tree and use it as binding source. Therefore, we must write DataContext and then property name.Dragonfly
B
1

Expanding on this very helpful post...If your ContextMenu has custom buttons or other objects within a ControlTemplate, I have combined the answer above with the answer from Closing ContextMenu with Templated MenuItems so that when a user clicks on the Button, the ContextMenu closes normally only using XAML. This took about 10 hours to put together. Hope it saves you time. Supports MVVM ICommand usage. I also used the Style for the ContextMenu from [this post][2] to elminate the 90's look.

<ListView.Resources>
    <ContextMenu x:Key="ItemContextMenu" Style="{StaticResource HorizontalContextMenu}">
        <MenuItem>
            <MenuItem.Template>
                <ControlTemplate>
                    <Grid MinHeight="50" MinWidth="50">
                        <Button Style="{StaticResource CloseAppButton}" Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" >
                            <Button.Triggers>
                                <EventTrigger RoutedEvent="Button.Click">
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ContextMenu.IsOpen)" Storyboard.Target="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <sys:Boolean>False</sys:Boolean>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Button.Triggers>
                        </Button>
                    </Grid>
                </ControlTemplate>
            </MenuItem.Template>
        </MenuItem>

        <MenuItem>
            <MenuItem.Template>
                <ControlTemplate>
                    <Grid MinHeight="50" MinWidth="50">
                        <Button Style="{StaticResource AddButton}" Command="{Binding Path=DataContext.TestCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" >
                            <Button.Triggers>
                                <EventTrigger RoutedEvent="Button.Click">
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ContextMenu.IsOpen)" Storyboard.Target="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <sys:Boolean>False</sys:Boolean>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Button.Triggers>
                        </Button>
                    </Grid>
                </ControlTemplate>
            </MenuItem.Template>
        </MenuItem>

        <MenuItem>
            <MenuItem.Template>
                <ControlTemplate>
                    <Grid MinHeight="50" MinWidth="50">
                        <Button Style="{StaticResource PluginInfoButton}" Command="{Binding Path=DataContext.TestCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" >
                            <Button.Triggers>
                                <EventTrigger RoutedEvent="Button.Click">
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ContextMenu.IsOpen)" Storyboard.Target="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}}">
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <sys:Boolean>False</sys:Boolean>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Button.Triggers>
                        </Button>
                    </Grid>
                </ControlTemplate>
            </MenuItem.Template>
        </MenuItem>
    </ContextMenu>

</ListView.Resources>
<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}" >
        <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    </Style>
</ListView.ItemContainerStyle>
Borlow answered 2/5, 2021 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.