ListView和TreeView大家都知道,配合ItemTemplate可以做出很好看的列表。如果需要其中某一项进行操作,首先想到的肯定是给ItemTemplate添加右键菜单,比如说把这段XML代码放到ListView的里面:
<ListView.ContextMenu>
<ContextMenu>
<MenuItem x:Name="ContextMenu1" Header="菜单项" Click="ContextMenu1_Click"/>
</ContextMenu>
</ListView.ContextMenu>
可是WPF有一个极为愚蠢的设定,右键的时候并不是默认选定当前项的,那么从ListView的SelectedItem等相关属性一概是看不出用户对着哪一项点的右键。并且菜单事件的sender就只能看到ContextMenu自己,也看不到其他有用信息。于是用户必须先左键选中,再右键菜单,简直愚蠢透顶。
我参考的方法是这篇:在WPF的TreeView中实现右键选定
给Item添加PreviewMouseRightButtonDown事件,就是鼠标右键点下瞬间:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="ListViewItem.PreviewMouseRightButtonDown" Handler="ListViewItem_PreviewMouseRightButtonDown"/>
</Style>
</ListView.ItemContainerStyle>
然后用如下代码让右键点下瞬间选中当前项:
private void ListViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
var ListViewItem = VisualUpwardSearch<ListViewItem>(e.OriginalSource as DependencyObject) as ListViewItem;
if (ListViewItem != null)
{
ListViewItem.Focus();
e.Handled = true;
}
}
static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
{
while (source != null && source.GetType() != typeof(T))
source = VisualTreeHelper.GetParent(source);
return source;
}
但是年代久远或者其他什么原因,很遗憾这段代码并没有实现预期功能,右键菜单还是找不到被点击对象。不过在调试过程中发现了一点,就是强制转换的ListViewItem的确是右键点击的当前项,于是方案如下:
1、准备一个全局变量用来保存ListViewItem或是它所绑定的DataContext,因为很多时候需要的其实是当前项的数据而已;比如说我们用的是DataVar类型的变量data,稍微修改一下前面的代码:
private void ListViewItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
var ListViewItem = VisualUpwardSearch<ListViewItem>(e.OriginalSource as DependencyObject) as ListViewItem;
if (ListViewItem != null)
{
data = ListViewItem.DataContext as DataVar;
ListViewItem.Focus();
e.Handled = true;
}
}
static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
{
while (source != null && source.GetType() != typeof(T))
source = VisualTreeHelper.GetParent(source);
return source;
}
2、ContextMenu的代码照样写,改为从全局变量data获取当前项的信息:
private void ContextMenu1_Click(object sender, RoutedEventArgs e)
{
if (data is null) return;
//然后该干什么干什么
}