【问题标题】:Detect ListViewitem where rightTapped event happened检测发生 rightTapped 事件的 ListViewitem
【发布时间】:2020-12-03 06:30:29
【问题描述】:

有什么方法可以在没有SelectionChanged 事件和相关来源的情况下从RightTappedRoutedEventArgs e 获取ListItem,因为这个ListViewSelectionMode="none"。如果 SelectionMode="none" 无法做到这一点,是否可以使用其他选择类型,但仍然没有选择更改事件?

Item xaml 模板如下。

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

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

【问题讨论】:

    标签: c# windows-runtime windows-store-apps


    【解决方案1】:

    我知道这是一个老问题,但我这周偶然发现了这个问题。

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

    • 键盘激活(Shift+F10 和键盘上的“上下文菜单”按钮都会触发 RightTapped 事件since Windows 8.1
    • 如果您的ItemTemplate 包含具有自己的DataContexts 的其他元素,例如&lt;Button&gt;(甚至是隐含的)。

    对于第一种情况(由键盘激活),e.OriginalSource 没有 DataContext。但是,e.OriginalSource 已经是 ListViewItem!这样你就完成了!

    但是,对于第二种情况(包含具有自己的 DataContexts 的元素),查看 DataContext 可能会为您提供一个孩子的 DataContext,而不是您想要的!

    查找 ListViewItem 的最可靠方法就是沿着树向上走(改编自 mm8's answer 类似的问题):

    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


    编辑历史记录:

    • 添加了关于如何从任意事件中获取 ListViewItem 的说明。
    • 为获取 ListViewItems 添加了更强大的方法。

    【讨论】:

      【解决方案2】:
      <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;
         ...
      

      中提琴!已点击的项目。

      现在 ListView 的正确上下文菜单已完成;)

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

      【讨论】:

        猜你喜欢
        • 2012-04-13
        • 1970-01-01
        • 1970-01-01
        • 2011-06-19
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        • 2019-11-01
        相关资源
        最近更新 更多