我的每个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>
答案 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
获取父ListViewItempublic 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
)。