检测发生右点击事件的列表视图项

本文关键字:列表 视图 事件 检测 | 更新日期: 2024-10-29 18:35:54

有没有办法在没有SelectionChanged事件和相关来源的情况下从RightTappedRoutedEventArgs e获取ListItem,因为这ListView SelectionMode="none".如果这在SelectionMode="none"中无法实现,它是否可用于其他选择类型,但仍然没有选择更改事件?

下面的项 xaml 模板。

<ListView.ItemTemplate>
 <DataTemplate>
   <Grid Height="56" Width="300">
     <Image .../>
    <TextBlock .../>
   </Grid>
 </DataTemplate>
</ListView.ItemTemplate>

由于一些实验,我有子类化的ListView(具有当前未使用的功能)和子类化的ListViewItem,处理RightTapped。也许有什么方法可以将this附加到事件中?我认为将其存储为子类化 ListView 中的选择结果是一种不好的行为。

检测发生右点击事件的列表视图项

我意识到这是一个老问题,但我本周偶然发现了它。

Crea7or的答案在许多情况下是正确的(一旦你有了他们所演示的DataContext,你通常可以使用ContainerFromItem来获取ListViewItem),但它在两个重要场景中也不起作用:

  • 键盘激活(自 Windows 8.1 以来,Shift+F10 和键盘上的"上下文菜单"按钮都将触发 RightTap 事件)
  • 如果您的ItemTemplate包含其他元素及其自己的DataContext,例如<Button>(甚至是隐式)。

对于第一种方案(由键盘激活),e.OriginalSource没有数据上下文。但是,e.OriginalSource已经是ListViewItem了!大功告成!

但是,对于第二种情况(包含具有自己的 DataContext 的元素),查看 DataContext 可能会获得子项的数据上下文,而不是您想要的!

查找ListViewItem的最可靠方法是简单地走上树(改编自mm8对类似问题的回答):

private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
    var parent = VisualTreeHelper.GetParent(dependencyObject);
    if (parent == null) return null;
    var parentT = parent as T;
    return parentT ?? FindParent<T>(parent);
}
// ... in your code ...
ListViewItem lvi = e.OriginalSource as ListViewItem;
if (lvi == null)
{
  lvi = FindParent<ListViewItem>(e.OriginalSource as DependencyObject);
}
<小时 />

如果您确信第二种方案不适用,则可以采用更简单的方法从任意事件中获取 ListViewItem

var listViewItem = e.OriginalSource as ListViewItem;
if (listViewItem == null)
{
  var dataContext = (e.OriginalSource as FrameworkElement).DataContext;
  listViewItem = (sender as ListView).ContainerFromItem(dataContext) as ListViewItem;
}
<小时 />

但是,这个问题的原始答案实际上想要获取支持 ListViewItem 的实际对象。

若要在处理上述所有其他方案的同时查找可靠表示的实际对象,请获取 ListViewItem 并使用 ItemsControl.ItemFromContainer 方法获取实际对象:

private void itemsListBoxRightTapped( object sender, RightTappedRoutedEventArgs e )
{
    MyItemType item;
    ListViewItem lvi = e.OriginalSource as ListViewItem;
    if (listViewItem == null)
    {
        // Use earlier definition for FindParent.
        listViewItem = FindParent<ListViewItem>(e.OriginalSource as DependencyObject);
    }
    item = (sender as ListView).ItemFromContainer(listViewItem) as MyItemType;
    // We have the item!
}

ItemsControl还有其他一些非常好的帮助程序方法,比如IndexFromContainer。

<小时 />

编辑历史记录:

  • 添加了有关如何从任意事件中获取列表视图项的说明。
  • 添加了用于获取列表视图项的更强大的方法。
<小时 />

免责声明:我为Microsoft工作。

<ListView.ItemTemplate>
 <DataTemplate>
   <Grid Height="56" Width="300" IsHitTestVisible="False">
...

所以现在我看到总是Border作为原始发件人。它以前是TextBoxImage的。

然后在:

private void itemsListBoxRightTapped( object sender, RightTappedRoutedEventArgs e )
{
  Border clickBorder = e.OriginalSource as Border;
  if ( clickBorder != null )
  {
     MyItemType selectedItem = clickBorder.DataContext as MyItemType;
   ...

中提琴!点击的项目。

现在,列表视图的正确上下文菜单已完成;)

更新:Windows 通用应用程序具有ListViewItemPresenter而不是Border