Gitea回购我有一个带有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
s时,应该会出现一个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}} />
然后我发现了这个:当ListView单击时,WPF获取ContextMenu项的名称,但我不喜欢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);
}
但现在我发现了一个错误:
委托System.Action不使用1个参数
我安装了NuGet包GalaSoft.MvvmLight
,因为我没有RelayCommand
。这是正确的,还是我必须创建一个类?
发布于 2021-03-12 12:56:59
您的原始CommandParameter
绑定无法工作,因为ContextMenu
并不是与其关联的控件相同的可视树的一部分,而且祖先类型是错误的(ListBox
而不是ListView
)。下面的原始绑定可以找到ListBox
__类型的第一个父类,获取它的SelectedItem
并将其赋值为CommandParameter
。
<MenuItem CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, ListBox, 1}} />
相反,您可以做的是利用以下事实:ContextMenu
的ContextMenu
属性包含对关联控件的引用(此处为ListView
)。因此,下面的绑定转换为查找父ContextMenu
__,获取其关联控件的SelectedItem
并将其赋值为CommandParameter
。
<MenuItem Header="Remove"
Command="{Binding RemoveItem}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
委托System.Action不使用1个参数
由于使用了错误的命令类型,因此会得到此错误。RelayCommand
构造函数接受Action
类型的执行委托。此删除门不接受任何参数。
public RelayCommand(Action execute, bool keepTargetAlive = false)
您要寻找的是采用RelayCommand
的通用Action
。
public RelayCommand(Action<T> execute, bool keepTargetAlive = false)
调整您的属性以使用RelayCommand<string>
,这里不需要转换为string
。
public ICommand RemoveItem
{
get { return _removeItem ?? (_removeItem = new RelayCommand<string>(RemoveItemCommand)); }
}
更新您的评论。您的RemoveItem
命令是在窗口的代码隐藏中定义的。由于您正在进行代码隐藏,并且直接访问您的控件以设置ItemsSource
等等,所以您可以在构造函数中将窗口的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不能转换为"System.String“。
这是因为items集合包含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.
}
https://stackoverflow.com/questions/66598877
复制相似问题