20

我有以下内容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>

现在我想在有界项目上右键单击显示上下文菜单,这将允许我在处理后面代码中的事件时检索所选项目。

我可以通过什么方式实现这一点?


[更新]

按照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>

但是在运行时,我收到了这个异常:

无法将“System.Windows.Controls.ContextMenu”类型的内容添加到“System.Object”类型的对象。标记文件“Mus​​icRepo_Importer;component/controls/trackgridcontrol.xaml”中的对象“System.Windows.Controls.ContextMenu”出错。

问题是什么?

4

3 回答 3

21

是的,使用上下文菜单添加 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>

注意:您需要将 ContextMenu 作为资源引用,并且不能在本地定义它。

这将为整行启用上下文菜单。:)

另请参阅我处理了该PreviewMouseLeftButtonDown事件,因此我可以确保该项目具有焦点(并且是您查询 ListView 时当前选择的项目)。我发现在应用程序之间更改焦点时我必须这样做,在您的情况下可能并非如此。

更新

在代码隐藏文件中,您需要遍历可视化树以查找列表容器项,因为事件的原始源可以是项模板的元素(例如堆栈面板)。

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();
}

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);
  }
}

我希望这些附加信息有所帮助。

丹尼斯

于 2009-04-14T23:03:51.300 回答
9

丹尼斯,

喜欢这个例子,但是我没有发现你的 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>

然后在 MenuItem_Click 事件中,我添加了如下代码:

private void menuItem_CopyUsername_Click(object sender, RoutedEventArgs e)
{
    Clipboard.SetText(mySelectedItem.Username);
}

mySelectedItem 用于 ListView.SelectedItem:

 <ListView x:Name="ListViewCreds" SelectedItem="{Binding mySelectedItem, UpdateSourceTrigger=PropertyChanged}" ....

如果有帮助请点我...

于 2012-08-16T13:47:13.417 回答
3

您可能对这个 SO 问题的答案感兴趣- 我有同样的问题,但对使用 mousedown 事件捕获被点击的项目不满意。有几个人回答了您可能感兴趣的简单易懂的解决方案。

摘要:您可以使用数据上下文将项目传递给处理程序,或命令+命令参数设置。

于 2009-07-15T18:08:32.163 回答