在 ListView 中获取鼠标光标下的项目

Getting the item under mouse cursor in ListView

这看起来像是 this or this 问题的重复。但我的问题是如何处理获得的 ListViewItem?

我已经设置了 ListView 这样的绑定

<ListView ItemsSource="{Binding Data}" ...>

哪里

public ObservableCollection<Item> Data { ... }

如何获得 Item(来自 ListViewItem)?


我尝试使用 mvvm 并绑定当前鼠标悬停的项目,类似于 this。但是后来我更跌跌撞撞了:

<ListView>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <!-- this will not work -->
                    <Setter Property="{Binding MouseoveredItem, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" Value="{Binding RelativeSource={RelativeSource Self}}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

我的意图清楚吗?我如何获得鼠标控制 Item?


我不敢相信没有人这样做过。这是代码隐藏尝试(以说明我的问题):

private void ListView_MouseMove(object sender, MouseEventArgs e)
{
    var item = VisualTreeHelper.HitTest(listView, Mouse.GetPosition(listView)).VisualHit;
    // find ListViewItem (or null)
    while (item != null && !(item is ListViewItem))
        item = VisualTreeHelper.GetParent(item);
    if (item != null)
    {
        ... // item is ListViewItem, how to convert ListViewItem it to Item
    }
}

我可以找到 ListViewItem,但我需要鼠标悬停 Item 的属性,这些属性显示为 SubItems 或隐藏。如何将 ListViewItemItem 的视觉视图)转换为 Item(这是 ListViewItem 所代表的)?

在您的 ViewModel 中使用它:

public ObservableCollection<Item> Data { ... }

public Item SelectedData { get; set; }

在您看来

<ListView ItemsSource="{Binding Data}" SelectedItem="{Binding SelectedData}" ...>

选择会更改,selecteddata 属性也会发生。

当您获得 "ListViewItem" 时,属性 "DataContext" 将 return 您的 "Item"。

在以下代码片段中,ListView 对象与 ObservableCollection<IDataItem> 集合绑定,其中 IDataItem 是自定义接口并继承了 INotifyPropertyChanged.

在.xaml:

MouseMove="listView_OnMouseMove"

在.xaml.cs:

private void listView_OnMouseMove(object sender, MouseEventArgs e)
{        
    if (!(e.Source is UIElement selectedObject))
        return;

    var mousePosition = e.GetPosition(selectedObject);
    var dataContextObject = listView.GetObjectAtPoint<ListViewItem>(mousePosition);

    if (!(dataContextObject is IDataItem dataItem))
        return;

    // Deal with the selectedObject under the mouse cursor here
}


// How to get Item under cursor in WPF ListView
// https://www.py4u.net/discuss/1453642 - Answer #2
public static object GetObjectAtPoint<ItemContainer>(this ItemsControl control, Point p) 
    where ItemContainer : DependencyObject
{
    // ItemContainer - can be ListViewItem, or TreeViewItem and so on(depends on control)
    var obj = control.GetContainerAtPoint<ItemContainer>(p);
    if (obj == null)
        return null;

    return control.ItemContainerGenerator.ItemFromContainer(obj);
}

private static ItemContainer GetContainerAtPoint<ItemContainer>(this ItemsControl control, Point p) 
    where ItemContainer : DependencyObject
{
    var result = VisualTreeHelper.HitTest(control, p);
    var obj = result.VisualHit;

    while (VisualTreeHelper.GetParent(obj) != null && !(obj is ItemContainer))
    {
        obj = VisualTreeHelper.GetParent(obj);
    }

    // Will return null if not found
    return obj as ItemContainer;
}