确定执行 ContextMenu MenuItem 时在 ListView 中单击了哪个 ListViewItem
我正在尝试使用列表视图中的上下文菜单来运行一些代码,这些代码需要其源自哪个项目的数据。
我最初只是这样做:
XAML:
<ListView x:Name="lvResources" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.Resources>
<ContextMenu x:Key="resourceContextMenu">
<MenuItem Header="Get Metadata" Name="cmMetadata" Click="cmMetadata_Click" />
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource resourceContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
...
C#:
private void cmMetadata_Click(object sender, RoutedEventArgs e)
{
// code that needs item data here
}
但我发现原始列表视图项目无法以这种方式访问。
我读过一些关于如何解决这个问题的策略,比如拦截 MouseDown 事件并为单击的 listviewitem 设置一个私有字段,但这对我来说不太合适,因为传递数据似乎有点老套方式。 WPF 应该很简单,对吧? :) 我已经读过这个SO问题并且这个MSDN 论坛问题,但我仍然不确定如何真正做到这一点,因为这两篇文章似乎都不适合我的情况。 有没有更好的方法将单击的项目传递到上下文菜单?
谢谢!
I'm trying to use the context menu in a listview to run some code that requires data from which item it originated from.
I initially just did this:
XAML:
<ListView x:Name="lvResources" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.Resources>
<ContextMenu x:Key="resourceContextMenu">
<MenuItem Header="Get Metadata" Name="cmMetadata" Click="cmMetadata_Click" />
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource resourceContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
...
C#:
private void cmMetadata_Click(object sender, RoutedEventArgs e)
{
// code that needs item data here
}
But I found that the originating listview item was not accessible that way.
I've read some tactics about how to get around this, like intercepting the MouseDown event and setting a private field to the listviewitem that was clicked, but that doesn't sit well with me as it seems a bit hacky to pass data around that way. And WPF is supposed to be easy, right? :) I've read this SO question and this MSDN forum question, but I'm still not sure how to really do this, as neither of those articles seem to work in my case. Is there a better way to pass the item that was clicked on through to the context menu?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
与 Charlie 的答案类似,但不需要更改 XAML。
Similar to Charlie's answer, but shouldn't require XAML changes.
在 cmMetadata_Click 处理程序中,您只需查询 lvResources.SelectedItem 属性,因为可以从单击处理程序所在的代码隐藏文件访问 lvResources。它并不优雅,但它可以工作。
如果您想更优雅一点,您可以更改设置上下文菜单的位置。 例如,您可以尝试这样的操作:
它的作用是插入 ListViewItem 的模板,然后您可以使用方便的 TemplatedParent 快捷方式将 ListViewItem 分配给菜单项的 DataContext。
现在您的代码隐藏如下所示:
显然,缺点是您现在需要完成 ListViewItem 的模板,但我确信您可以很快找到一个适合您需求的模板。
Well in the cmMetadata_Click handler, you can just query the lvResources.SelectedItem property, since lvResources will be accessible from the code-behind file that the click handler is located in. It's not elegant, but it will work.
If you want to be a little more elegant, you could change where you set up your ContextMenu. For example, you could try something like this:
What this does is plug in a template for your ListViewItem, and then you can use the handy TemplatedParent shortcut to assign the ListViewItem to the DataContext of your menu item.
Now your code-behind looks like this:
Obviously the downside is you will now need to complete the template for a ListViewItem, but I'm sure you can find one that will suit your needs pretty quickly.
所以我决定尝试实现一个命令解决方案。 我对它现在的运作方式非常满意。
首先,创建我的命令:
接下来在我的自定义列表视图控件中,我添加了一个与构造函数绑定的新命令:
并且还添加了事件处理程序:
我已经使用样式选择器来动态地将样式分配给列表视图项,所以改为为了在 xaml 中执行此操作,我必须在代码隐藏中设置绑定。 不过,您也可以在 xaml 中执行此操作:
我更喜欢此解决方案的感觉,而不是尝试在鼠标单击时设置字段并尝试以这种方式访问单击的内容。
So I decided to try and implement a command solution. I'm pretty pleased with how it's working now.
First, created my command:
Next in my custom listview control, I added a new command binding to the constructor:
And also there, added the event handlers:
I was already using a style selector to dynamically assign styles to the listview items, so instead of doing this in the xaml, I have to set the binding in the codebehind. You could do it in the xaml as well though:
I like the feel of this solution much better than attempting to set a field on mouse click and try to access what was clicked that way.