WPF从ListViewItem上的ContextMenu获取引用的项

时间:2010-10-25 15:03:22

标签: wpf contextmenu

我的每个ListView都有ContextMenu ListViewItem Click个事件, 如何在事件处理程序中检测到在此ContextMenu中单击了哪个Item? 我需要商品ID

 <Style TargetType="{x:Type ListViewItem}">

。 。

 <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="tv:TreeListViewItem">
                        <Grid>
                            <Grid.ContextMenu>
                                <ContextMenu>
                                    <MenuItem Header="Open in current tab" Click="MenuItemCurrentTab_Click"/>
                                    <MenuItem Header="Open in new tab" Click="MenuItemNewTab_Click"/>
                                </ContextMenu>
                            </Grid.ContextMenu>

4 个答案:

答案 0 :(得分:6)

请参阅this主题..

按照与链接的答案相同的方式

<Grid.ContextMenu> 
    <ContextMenu> 
        <MenuItem Header="Open in current tab"
                  Click="MenuItemCurrentTab_Click"
                  CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/>

...

private void MenuItemCurrentTab_Click(object sender, RoutedEventArgs e)
{
    MenuItem menuItem = sender as MenuItem;
    if (menuItem != null)
    {
        ContextMenu parentContextMenu = menuItem.CommandParameter as ContextMenu;
        if (parentContextMenu != null)
        {
            ListViewItem listViewItem = parentContextMenu.PlacementTarget as ListViewItem;
        }
    } 
}

<强>更新

添加此项以从Grid

获取父ListViewItem
public T GetVisualParent<T>(object childObject) where T : Visual
{
    DependencyObject child = childObject as DependencyObject;
    while ((child != null) && !(child is T))
    {
        child = VisualTreeHelper.GetParent(child);
    }
    return child as T;
}

private void MenuItemCurrentTab_Click(object sender, RoutedEventArgs e)
{
    MenuItem menuItem = sender as MenuItem;
    if (menuItem != null)
    {
        ContextMenu parentContextMenu = menuItem.CommandParameter as ContextMenu;
        if (parentContextMenu != null)
        {
            Grid grid = parentContextMenu.PlacementTarget as Grid;
            ListViewItem listViewItem = GetVisualParent<ListViewItem>(grid);
        }
    } 
}

答案 1 :(得分:3)

    private void MenuItemCurrentTab_Click(object sender, RoutedEventArgs e)
    {
        MenuItem menuItem = (MenuItem)e.Source;
        ContextMenu menu = (ContextMenu)menuItem.Parent;
        ListViewItem item = (ListViewItem)menu.PlacementTarget;
        // do something with item
    }

但是创建单个ContextMenu可能更好,给它指定正确的名称,并将其用于所有列表视图项。

答案 2 :(得分:0)

ListViewItem item = myListView.SelectedItem as ListViewItem;

当右键单击该项目时,似乎工作得很好。

答案 3 :(得分:0)

一个反复出现的问题,尽管有许多尝试可以解决,但是都有缺点。例如,此处接受的答案假设每个ListViewItem都有自己的ContextMenu。这是可行的,但是特别是对于大量列表项,在XAML复杂性方面具有相当大的成本,并且速度可能很慢。确实根本没有必要。如果我们仅在ContextMenu上使用单个ListView,则建议使用其他解决方案

 <MenuItem CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />

这似乎一眼就解决了问题(PlacementTarget指向ListView,其SelectedItem指向列表项,因此菜单项处理程序可以使用{{1 }}来获取原始列表项),但是不幸的是,如果CommandParameter启用了多项选择(ListView会指向所选项之一,但不一定指向当前单击的项),则失败,或者我们使用SelectedItem来禁用右键单击的选择(可以说,这是唯一与多重选择有关的逻辑选择。)

但是,有一种方法具有所有优点:

  • ListView.PreviewMouseRightButtonDown上单独ContextMenu
  • 适用于所有选择方案,单个,多个,已禁用;
  • 即使有多项选择,它也会将当前悬停的项目传递给处理程序。

考虑以下ListView

ListView

<ListView ContextMenuOpening="ListView_ContextMenuOpening"> <ListView.ContextMenu> <ContextMenu> <MenuItem Header="Menu1" Click="Menu1_Click" CommandParameter="{Binding Parent, RelativeSource={RelativeSource Self}}" /> </ContextMenu> </ListView.ContextMenu> </ListView> 用于传递CommandParameter的父级,即。 MenuItem本身。但是主要技巧是菜单打开处理程序:

ContextMenu

在此处理程序中,我们仍然知道事件的原始源,即列表项private void ListView_ContextMenuOpening(object sender, ContextMenuEventArgs e) { var menu = (e.Source as FrameworkElement).ContextMenu; menu.Tag = (FrameworkElement)e.OriginalSource; } 的根FrameworkElement。让我们将其存储在菜单的DataTemplate中,以便以后检索。

Tag

在菜单单击处理程序中,我们可以查找存储在命令参数中的原始private void Menu1_Click(object sender, RoutedEventArgs e) { if (sender is MenuItem menu) if (menu.CommandParameter is ContextMenu context) if (context.Tag is FrameworkElement item) if (item.DataContext is DataType data) { //process data } } ,从中可以查找之前存储的列表项的根ContextMenu,并最终获得存储在列表项中的对象(类型为FrameworkElement)。