WPF 列表视图上下文菜单
WPF ListView ContextMenu
Gitea Repo
我有一个带有 ListView
的 WPF C# 应用程序,里面有一个 GridView
.
<ListView Name="Entries">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn Header="Type" Width="Auto" DisplayMemberBinding="{Binding Type}" />
<GridViewColumn Header="Title" Width="Auto" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Header="Date" Width="Auto" DisplayMemberBinding="{Binding Date}" />
<GridViewColumn Header="Tags" Width="Auto" DisplayMemberBinding="{Binding Tags}" />
<GridViewColumn Header="Categories" Width="Auto" DisplayMemberBinding="{Binding Categories}" />
</GridView>
</ListView.View>
</ListView>
当我右键单击 ListViewItem
时,应该出现 ContextMenu
,当我单击它时,它应该执行一个函数。
像这样:
private void EntryClick(<identifier of click>) {
MessageBox.Show("Clicked " + <maybe title to identify what i clicked>);
}
我到处都能找到这个,但我不知道如何处理它:
<MenuItem ... CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor,ListBox,1}} />
然后我发现了这个: 但是我什么都没有 item.Name
编辑:
我加了
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
</ContextMenu>
</ListView.ContextMenu>
和
using GalaSoft.MvvmLight.Command;
private ICommand _removeItem;
public ICommand RemoveItem
{
get { return _removeItem ?? (_removeItem = new RelayCommand(p => RemoveItemCommand((string)p))); }
}
private void RemoveItemCommand(string item)
{
if (!string.IsNullOrEmpty(item))
MessageBox.Show(item);
}
但现在我得到这个错误:
Delegate System.Action does not take 1 arguments
我安装了 NuGet 包 GalaSoft.MvvmLight
,因为我没有 RelayCommand
。这是正确的还是我必须创建一个 class?
您原来的 CommandParameter
绑定不起作用,因为 ContextMenu
与其关联的控件不属于同一可视化树,并且祖先类型错误(ListBox
而不是 ListView
)。下面的原始绑定转换为 找到类型 ListBox
的第一个父级,获取它的 SelectedItem
并将其分配为 CommandParameter
.
<MenuItem CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, ListBox, 1}} />
您可以改为利用 ContextMenu
的 PlacementTarget
属性 包含对关联控件的引用(此处为 ListView
)这一事实。所以下面的绑定转化为找到父ContextMenu
,获取其关联控件的SelectedItem
并将其分配为CommandParameter
.
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
Delegate System.Action does not take 1 arguments
您收到此错误是因为您使用了错误的命令类型。一个RelayCommand
constructor takes an execute delegate of type Action
。该委托不接受任何参数。
public RelayCommand(Action execute, bool keepTargetAlive = false)
您要查找的是通用 RelayCommand<T>
that takes an Action<T>
。
public RelayCommand(Action<T> execute, bool keepTargetAlive = false)
调整您的 属性 以使用 RelayCommand<string>
,无需在此处转换为 string
。
public ICommand RemoveItem
{
get { return _removeItem ?? (_removeItem = new RelayCommand<string>(RemoveItemCommand)); }
}
更新您的评论。您的 RemoveItem
命令在 window 的代码隐藏中定义。由于无论如何您都在进行代码隐藏并直接访问控件以设置 ItemsSource
等等,因此您可以在构造函数中将 window 的 DataContext
设置为它自己。
public MainWindow()
{
InitializeComponent();
// ...your other code.
DataContext = this;
}
数据上下文是在控件中继承的,因此要访问数据上下文上的RemoveItem
命令,您可以使用与上面相同的方法与PlacementTarget
。
<MenuItem Header="Remove"
Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
请注意,有无数种方法可以解决此问题,使用 DataContext
只是其中一种,但由于不清楚您采用的是哪种设计方法,因此很难给出明确的答案。考虑研究 MVVM 模式,这将使这类问题变得容易得多。
更新您的评论,您得到 InvalidCastException
。
hexo_gui.Entries" cant be converted to "System.String".
这是因为项目集合包含 Entries
、 而非 string
类型的项目,但在您的命令中您期望 string
,因此例外。调整您的命令以期待一个 Entries
实例。
public ICommand RemoveItem => _removeItem ?? (_removeItem = new RelayCommand<Entries>(RemoveItemCommand));
private void RemoveItemCommand(Entries item)
{
// No item was selected.
if (item == null)
return;
// Do something with the item.
}
Gitea Repo
我有一个带有 ListView
的 WPF C# 应用程序,里面有一个 GridView
.
<ListView Name="Entries">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridView.ColumnHeaderContainerStyle>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn Header="Type" Width="Auto" DisplayMemberBinding="{Binding Type}" />
<GridViewColumn Header="Title" Width="Auto" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Header="Date" Width="Auto" DisplayMemberBinding="{Binding Date}" />
<GridViewColumn Header="Tags" Width="Auto" DisplayMemberBinding="{Binding Tags}" />
<GridViewColumn Header="Categories" Width="Auto" DisplayMemberBinding="{Binding Categories}" />
</GridView>
</ListView.View>
</ListView>
当我右键单击 ListViewItem
时,应该出现 ContextMenu
,当我单击它时,它应该执行一个函数。
像这样:
private void EntryClick(<identifier of click>) {
MessageBox.Show("Clicked " + <maybe title to identify what i clicked>);
}
我到处都能找到这个,但我不知道如何处理它:
<MenuItem ... CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor,ListBox,1}} />
然后我发现了这个: item.Name
编辑:
我加了
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
</ContextMenu>
</ListView.ContextMenu>
和
using GalaSoft.MvvmLight.Command;
private ICommand _removeItem;
public ICommand RemoveItem
{
get { return _removeItem ?? (_removeItem = new RelayCommand(p => RemoveItemCommand((string)p))); }
}
private void RemoveItemCommand(string item)
{
if (!string.IsNullOrEmpty(item))
MessageBox.Show(item);
}
但现在我得到这个错误:
Delegate System.Action does not take 1 arguments
我安装了 NuGet 包 GalaSoft.MvvmLight
,因为我没有 RelayCommand
。这是正确的还是我必须创建一个 class?
您原来的 CommandParameter
绑定不起作用,因为 ContextMenu
与其关联的控件不属于同一可视化树,并且祖先类型错误(ListBox
而不是 ListView
)。下面的原始绑定转换为 找到类型 ListBox
的第一个父级,获取它的 SelectedItem
并将其分配为 CommandParameter
.
<MenuItem CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, ListBox, 1}} />
您可以改为利用 ContextMenu
的 PlacementTarget
属性 包含对关联控件的引用(此处为 ListView
)这一事实。所以下面的绑定转化为找到父ContextMenu
,获取其关联控件的SelectedItem
并将其分配为CommandParameter
.
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
Delegate System.Action does not take 1 arguments
您收到此错误是因为您使用了错误的命令类型。一个RelayCommand
constructor takes an execute delegate of type Action
。该委托不接受任何参数。
public RelayCommand(Action execute, bool keepTargetAlive = false)
您要查找的是通用 RelayCommand<T>
that takes an Action<T>
。
public RelayCommand(Action<T> execute, bool keepTargetAlive = false)
调整您的 属性 以使用 RelayCommand<string>
,无需在此处转换为 string
。
public ICommand RemoveItem
{
get { return _removeItem ?? (_removeItem = new RelayCommand<string>(RemoveItemCommand)); }
}
更新您的评论。您的 RemoveItem
命令在 window 的代码隐藏中定义。由于无论如何您都在进行代码隐藏并直接访问控件以设置 ItemsSource
等等,因此您可以在构造函数中将 window 的 DataContext
设置为它自己。
public MainWindow()
{
InitializeComponent();
// ...your other code.
DataContext = this;
}
数据上下文是在控件中继承的,因此要访问数据上下文上的RemoveItem
命令,您可以使用与上面相同的方法与PlacementTarget
。
<MenuItem Header="Remove"
Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
请注意,有无数种方法可以解决此问题,使用 DataContext
只是其中一种,但由于不清楚您采用的是哪种设计方法,因此很难给出明确的答案。考虑研究 MVVM 模式,这将使这类问题变得容易得多。
更新您的评论,您得到 InvalidCastException
。
hexo_gui.Entries" cant be converted to "System.String".
这是因为项目集合包含 Entries
、 而非 string
类型的项目,但在您的命令中您期望 string
,因此例外。调整您的命令以期待一个 Entries
实例。
public ICommand RemoveItem => _removeItem ?? (_removeItem = new RelayCommand<Entries>(RemoveItemCommand));
private void RemoveItemCommand(Entries item)
{
// No item was selected.
if (item == null)
return;
// Do something with the item.
}