C# WPF:显示 GridView 项目的上下文菜单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/747872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF: Displaying a Context Menu for a GridView's Items
提问by Andreas Grech
I have the following GridView
:
我有以下几点GridView
:
<ListView Name="TrackListView" ItemContainerStyle="{StaticResource itemstyle}">
<ListView.View>
<GridView>
<GridViewColumn Header="Title" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Artist" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Artist.Name}" />
<GridViewColumn Header="Album" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Name}"/>
<GridViewColumn Header="Length" Width="100" HeaderTemplate="{StaticResource BlueHeader}"/>
</GridView>
</ListView.View>
</ListView>
Now I would like to display a context menu on a right click on a bounded item that will allow me to retrieve the item selected when I handle the event in the code behind.
现在,我想在有界项目上单击鼠标右键显示一个上下文菜单,这将允许我在处理后面代码中的事件时检索所选项目。
In what possible way can I accomplish this?
我可以通过什么方式实现这一点?
[Update]
[更新]
Following Dennis Roche's code, I now have this:
按照Dennis Roche的代码,我现在有了这个:
<ListView Name="TrackListView" ItemContainerStyle="{StaticResource itemstyle}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnListViewItem_PreviewMouseLeftButtonDown" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add to Playlist"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Title" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Artist" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Artist.Name}" />
<GridViewColumn Header="Album" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Name}"/>
<GridViewColumn Header="Length" Width="100" HeaderTemplate="{StaticResource BlueHeader}"/>
</GridView>
</ListView.View>
</ListView>
But upon running, I am receiving this exception:
但是在运行时,我收到此异常:
Cannot add content of type 'System.Windows.Controls.ContextMenu' to an object of type 'System.Object'. Error at object 'System.Windows.Controls.ContextMenu' in markup file 'MusicRepo_Importer;component/controls/trackgridcontrol.xaml'.
无法将“System.Windows.Controls.ContextMenu”类型的内容添加到“System.Object”类型的对象。标记文件“MusicRepo_Importer;component/controls/trackgridcontrol.xaml”中的对象“System.Windows.Controls.ContextMenu”出错。
What is the problem?
问题是什么?
采纳答案by Dennis
Yes, add a ListView.ItemContainerStyle with the Context Menu.
是的,使用上下文菜单添加 ListView.ItemContainerStyle。
<ListView>
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu">
...
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnListViewItem_PreviewMouseLeftButtonDown" />
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
NOTE: You need to reference the ContextMenu as a resource and cannot define it locally.
注意:您需要将 ContextMenu 作为资源引用,并且不能在本地定义它。
This will enable the context menu for the entire row. :)
这将为整行启用上下文菜单。:)
Also see that I handle the PreviewMouseLeftButtonDown
event so I can ensure the item is focused (and is the currently selected item when you query the ListView). I found that I had to this when changing focus between applications, this may not be true in your case.
另请参阅我处理该PreviewMouseLeftButtonDown
事件,以便确保该项目获得焦点(并且是您查询 ListView 时当前选定的项目)。我发现在应用程序之间改变焦点时我不得不这样做,在你的情况下这可能不是真的。
Updated
更新
In the code behind file you need to walk-up the visual tree to find the list container item as the original source of the event can be an element of the item template (e.g. a stackpanel).
在代码隐藏文件中,您需要遍历可视化树以查找列表容器项目,因为事件的原始来源可以是项目模板的元素(例如堆栈面板)。
void OnListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.Handled)
return;
ListViewItem item = MyVisualTreeHelper.FindParent<ListViewItem>((DependencyObject)e.OriginalSource);
if (item == null)
return;
if (item.Focusable && !item.IsFocused)
item.Focus();
}
The MyVisualTreeHelper
that is use a wrapper that I've written to quickly walk the visual tree. A subset is posted below.
的MyVisualTreeHelper
是使用包装,我已经写了快速走可视化树。下面贴出一个子集。
public static class MyVisualTreeHelper
{
static bool AlwaysTrue<T>(T obj) { return true; }
/// <summary>
/// Finds a parent of a given item on the visual tree. If the element is a ContentElement or FrameworkElement
/// it will use the logical tree to jump the gap.
/// If not matching item can be found, a null reference is returned.
/// </summary>
/// <typeparam name="T">The type of the element to be found</typeparam>
/// <param name="child">A direct or indirect child of the wanted item.</param>
/// <returns>The first parent item that matches the submitted type parameter. If not matching item can be found, a null reference is returned.</returns>
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
return FindParent<T>(child, AlwaysTrue<T>);
}
public static T FindParent<T>(DependencyObject child, Predicate<T> predicate) where T : DependencyObject
{
DependencyObject parent = GetParent(child);
if (parent == null)
return null;
// check if the parent matches the type and predicate we're looking for
if ((parent is T) && (predicate((T)parent)))
return parent as T;
else
return FindParent<T>(parent);
}
static DependencyObject GetParent(DependencyObject child)
{
DependencyObject parent = null;
if (child is Visual || child is Visual3D)
parent = VisualTreeHelper.GetParent(child);
// if fails to find a parent via the visual tree, try to logical tree.
return parent ?? LogicalTreeHelper.GetParent(child);
}
}
I hope this additional information helps.
我希望这些额外的信息有帮助。
Dennis
丹尼斯
回答by patjbs
You might be interested in the answers for this SO question- I had the same question but wasn't satisfied with using the mousedown event to capture the item that was clicked upon. Several people has responded with simple and easy to comprehend solutions that you might be interested in.
您可能对这个 SO 问题的答案感兴趣- 我有同样的问题,但对使用 mousedown 事件捕获被点击的项目并不满意。有几个人回答了您可能感兴趣的简单易懂的解决方案。
Summary : You can use the data context to pass the item through to the handler, or a command + command parameter setup.
摘要:您可以使用数据上下文将项目传递给处理程序,或者使用命令 + 命令参数设置。
回答by Omzig
Dennis,
丹尼斯,
Love the example, however I did not find any need for your Visual Tree Helper...
喜欢这个例子,但是我没有发现你的 Visual Tree Helper 有任何需要......
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu">
<MenuItem x:Name="menuItem_CopyUsername"
Click="menuItem_CopyUsername_Click"
Header="Copy Username">
<MenuItem.Icon>
<Image Source="/mypgm;component/Images/Copy.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="menuItem_CopyPassword"
Click="menuItem_CopyPassword_Click"
Header="Copy Password">
<MenuItem.Icon>
<Image Source="/mypgm;component/Images/addclip.png" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem x:Name="menuItem_DeleteCreds"
Click="menuItem_DeleteCreds_Click"
Header="Delete">
<MenuItem.Icon>
<Image Source="/mypgm;component/Images/Delete.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
Then inside the MenuItem_Click events I added code that looks like this:
然后在 MenuItem_Click 事件中,我添加了如下所示的代码:
private void menuItem_CopyUsername_Click(object sender, RoutedEventArgs e)
{
Clipboard.SetText(mySelectedItem.Username);
}
mySelectedItem is used on the ListView.SelectedItem:
mySelectedItem 用于 ListView.SelectedItem:
<ListView x:Name="ListViewCreds" SelectedItem="{Binding mySelectedItem, UpdateSourceTrigger=PropertyChanged}" ....
Please tick me if it helps...
如果有帮助请给我打勾...