【问题标题】:WPF ListView ContextMenuWPF ListView 上下文菜单
【发布时间】:2023-03-03 06:41:23
【问题描述】:

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>

当我右键单击ListViewItems 时,应该会出现一个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}} />

然后我发现了这个:WPF Get name of ListView item when ContextMenu clicked 但我对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。这是正确的还是我必须创建一个类?

【问题讨论】:

  • here
  • @Sinatr 检查我的编辑

标签: c# wpf listview binding contextmenu


【解决方案1】:

您原来的CommandParameter 绑定不起作用,因为ContextMenu 与其关联的控件不是同一可视树的一部分,并且祖先类型错误(ListBox 而不是ListView)。下面的原始绑定转换为找到ListBox 类型的第一个父级,获取其SelectedItem 并将其分配为CommandParameter

<MenuItem CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, ListBox, 1}} />

您可以做的是利用ContextMenuPlacementTarget 属性包含对关联控件(此处为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&lt;T&gt;,它采用Action&lt;T&gt;

public RelayCommand(Action<T> execute, bool keepTargetAlive = false)

调整您的属性以使用RelayCommand&lt;string&gt;,无需在此处转换为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.
}

【讨论】:

  • 我照你说的做了,但什么也没做。你能看看我的repo吗?
  • @kaaaxcreators 我调查了它,看看我的更新。
  • 错误System.InvalidCastException“hexo_gui.Entries”无法转换为“System.String”。还更新回购也许我做错了什么
  • @kaaaxcreators 查看我的更新,您希望命令中的类型错误。
猜你喜欢
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
相关资源
最近更新 更多