You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现WPF ListView鼠标滚轮横向逐项滚动

问题

我正在为WPF ListView实现横向滚动功能,目前该功能已可正常使用,但需要通过鼠标滚轮控制横向滚动。我已能捕获鼠标滚轮的上下滚动事件,现需在事件中调用可使ListView向左/向右逐项滚动的命令或方法。

现有C#代码:

private void UIElement_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    ListView listView= (ListView)sender;
 
    if (e.Delta < 0)
    {
        // Scrolls right, I need here to activate event that will scroll right,
        // something like listView.ScrollRightByOneItem()
    }
    else
    {
       // Scrolls left, I need here to activate event that will scroll left,
       // something like listView.ScrollLeftByOneItem()
    }
    e.Handled = true;
}

XAML代码:

<Grid>
    <ListView
        ItemsSource="{Binding Path=NotDeletedDevices}"
        MouseDoubleClick="ListView_MouseDoubleClick"
        PreviewMouseLeftButtonDown="ListView_PreviewMouseLeftButtonDown"
        PreviewMouseMove="ListView_PreviewMouseMove"
        SelectionMode="Single"
        PreviewMouseWheel="UIElement_OnPreviewMouseWheel"
        TouchDown="ListView_PreviewTouchDown"
        TouchMove="ListView_PreviewTouchMove">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>
</Grid>

请问是否存在可在.xaml.cs文件中实现ListView向左或向右逐项滚动的事件或命令?

解决方案

WPF的ListView并没有直接提供ScrollRightByOneItem这类内置方法,需要通过获取其内部的ScrollViewer,结合项的宽度或索引来实现逐项滚动。以下是两种可行的实现方式:

方法一:基于项宽度滚动(适合固定宽度的项)

首先需要一个辅助方法,通过可视化树找到ListView内部的ScrollViewer:

private ScrollViewer GetListViewScrollViewer(ListView listView)
{
    if (VisualTreeHelper.GetChildrenCount(listView) == 0)
        return null;

    // 获取ListView的外层Border
    var border = VisualTreeHelper.GetChild(listView, 0) as Border;
    return border?.Child as ScrollViewer;
}

然后修改PreviewMouseWheel事件处理逻辑,根据滚轮方向调整横向滚动偏移:

private void UIElement_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    ListView listView = (ListView)sender;
    var scrollViewer = GetListViewScrollViewer(listView);
    if (scrollViewer == null || listView.Items.Count == 0)
        return;

    // 获取单个项的宽度(以第一个项为参考)
    var firstItemContainer = listView.ItemContainerGenerator.ContainerFromIndex(0) as FrameworkElement;
    if (firstItemContainer == null)
        return;

    double itemWidth = firstItemContainer.ActualWidth;
    if (e.Delta < 0)
    {
        // 滚轮向下,向右滚动一个项的宽度
        scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + itemWidth);
    }
    else
    {
        // 滚轮向上,向左滚动一个项的宽度,避免滚动到负数范围
        scrollViewer.ScrollToHorizontalOffset(Math.Max(0, scrollViewer.HorizontalOffset - itemWidth));
    }
    e.Handled = true;
}

方法二:基于项索引滚动(精准对齐项,支持可变宽度)

同样使用上述的GetListViewScrollViewer辅助方法,然后通过BringIntoView让目标项滚动到可见区域:

private void UIElement_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    ListView listView = (ListView)sender;
    var scrollViewer = GetListViewScrollViewer(listView);
    if (scrollViewer == null || listView.Items.Count == 0)
        return;

    // 获取当前可见的第一个项的索引
    FrameworkElement firstVisibleItem = scrollViewer.Content as FrameworkElement;
    int firstVisibleIndex = listView.ItemContainerGenerator.IndexFromContainer(firstVisibleItem);

    if (e.Delta < 0)
    {
        // 向右滚动,定位到下一个项
        int targetIndex = Math.Min(firstVisibleIndex + 1, listView.Items.Count - 1);
        var targetItem = listView.ItemContainerGenerator.ContainerFromIndex(targetIndex) as FrameworkElement;
        targetItem?.BringIntoView();
    }
    else
    {
        // 向左滚动,定位到上一个项
        int targetIndex = Math.Max(firstVisibleIndex - 1, 0);
        var targetItem = listView.ItemContainerGenerator.ContainerFromIndex(targetIndex) as FrameworkElement;
        targetItem?.BringIntoView();
    }
    e.Handled = true;
}

说明

  • 方法一适合所有项宽度一致的场景,滚动距离固定;
  • 方法二通过项索引定位,即使项宽度不同也能精准滚动到对应项的位置;
  • 两种方式都需要通过VisualTreeHelper获取ListView内部的ScrollViewer,这是WPF中访问控件内部元素的常规方式。

内容的提问来源于stack exchange,提问作者Walde

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:20:45