首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WPF ListView ContextMenu

WPF ListView ContextMenu
EN

Stack Overflow用户
提问于 2021-03-12 11:15:07
回答 1查看 259关注 0票数 0

Gitea回购我有一个带有ListView的WPF C#应用程序,里面有一个GridView

代码语言:javascript
运行
复制
<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>

当我右键单击ListViewItems时,应该会出现一个ContextMenu,当我单击它时,它应该执行一个函数。就像这样:

代码语言:javascript
运行
复制
private void EntryClick(<identifier of click>) {
    MessageBox.Show("Clicked " + <maybe title to identify what i clicked>);
}

我到处都发现了这个,但我不知道该怎么做:

代码语言:javascript
运行
复制
<MenuItem ... CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor,ListBox,1}} />

然后我发现了这个:当ListView单击时,WPF获取ContextMenu项的名称,但我不喜欢item.Name

编辑:

我加了

代码语言:javascript
运行
复制
<ListView.ContextMenu>
    <ContextMenu>
        <MenuItem Header="Remove"
            Command="{Binding RemoveItem}"
            CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
    </ContextMenu>
</ListView.ContextMenu>

代码语言:javascript
运行
复制
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。这是正确的,还是我必须创建一个类?

EN

Stack Overflow用户

回答已采纳

发布于 2021-03-12 12:56:59

您的原始CommandParameter绑定无法工作,因为ContextMenu并不是与其关联的控件相同的可视树的一部分,而且祖先类型是错误的(ListBox而不是ListView)。下面的原始绑定可以找到ListBox__类型的第一个父类,获取它的SelectedItem并将其赋值为CommandParameter

代码语言:javascript
运行
复制
<MenuItem CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, ListBox, 1}} />

相反,您可以做的是利用以下事实:ContextMenuContextMenu属性包含对关联控件的引用(此处为ListView)。因此,下面的绑定转换为查找父ContextMenu__,获取其关联控件的SelectedItem并将其赋值为CommandParameter

代码语言:javascript
运行
复制
<MenuItem Header="Remove"
          Command="{Binding RemoveItem}"
          CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />

委托System.Action不使用1个参数

由于使用了错误的命令类型,因此会得到此错误。RelayCommand构造函数接受Action类型的执行委托。此删除门不接受任何参数。

代码语言:javascript
运行
复制
public RelayCommand(Action execute, bool keepTargetAlive = false)

您要寻找的是采用RelayCommand的通用Action

代码语言:javascript
运行
复制
public RelayCommand(Action<T> execute, bool keepTargetAlive = false)

调整您的属性以使用RelayCommand<string>,这里不需要转换为string

代码语言:javascript
运行
复制
public ICommand RemoveItem
{
    get { return _removeItem ?? (_removeItem = new RelayCommand<string>(RemoveItemCommand)); }
}

更新您的评论。您的RemoveItem命令是在窗口的代码隐藏中定义的。由于您正在进行代码隐藏,并且直接访问您的控件以设置ItemsSource等等,所以您可以在构造函数中将窗口的DataContext设置为它自己。

代码语言:javascript
运行
复制
public MainWindow()
{
   InitializeComponent();
   
   // ...your other code.

   DataContext = this;
}

数据上下文是在控件中继承的,因此要访问数据上下文上的RemoveItem命令,可以对PlacementTarget使用与上面相同的方法。

代码语言:javascript
运行
复制
<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实例。

代码语言:javascript
运行
复制
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.
}
票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66598877

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档