Detect ListViewitem where rightTapped event happened

时光毁灭记忆、已成空白 提交于 2020-12-11 06:23:23

问题


Is there any way to get the ListItem from RightTappedRoutedEventArgs e without SelectionChanged event and related sources because this ListView have SelectionMode="none". If this is not possible with SelectionMode="none", will it be available with other selection types, but still without selection change event?

Item xaml template below.

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

Due to some experiments, I have subclassed ListView (with currently unused functionality) and also subclassed ListViewItem with handling RightTapped. Maybe there is any way to attach this to event? Storing this as selection result in subclassed ListView is a not good behavior I think.


回答1:


I realize this is an old question, but I stumbled upon it this week.

Crea7or's answer is correct in many cases (once you have the DataContext as they demonstrate, you can often use ContainerFromItem to get the ListViewItem), but it also does not work in two important scenarios:

  • keyboard activation (Shift+F10 and the "context menu" button on keyboards will both trigger a RightTapped event since Windows 8.1)
  • if your ItemTemplate contains other elements with their own DataContexts, like a <Button> (even implicit).

For the first scenario (activated by keyboard), e.OriginalSource has no DataContext. However, e.OriginalSource is already the ListViewItem! So you're done!

However, for the second scenario (contains elements with their own DataContexts), looking at the DataContext might get you a DataContext for a child—not what you want!

The most robust way of looking up the ListViewItem is simply to walk up the tree (adapted from mm8's answer to a similar question):

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

If you are confident that the second scenario does not apply, you can take a simpler approach to get the ListViewItem from an arbitrary event:

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

However, the original answer to this question actually wanted to grab the actual object backing the ListViewItem.

To find the actual object being represented robustly—while handling all the additional scenarios outlined above, fetch the ListViewItem and use the ItemsControl.ItemFromContainer method to get the actual object:

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 has some other very nice helper methods, like IndexFromContainer.


Edit history:

  • added clarification on how to get ListViewItems from an arbitrary event.
  • added more robust method for fetching ListViewItems.



回答2:


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

So now I see always Border as original sender. It was TextBox or Image before.

then at:

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

viola! Tapped item.

Now correct context menu for ListView is done ;)

Update: Windows Universal apps have ListViewItemPresenter instead of Border.



来源:https://stackoverflow.com/questions/20668323/detect-listviewitem-where-righttapped-event-happened

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!