将ListViewItem滚动到ListView顶部

13
在WPF中,我知道可以使用ListView.ScrollIntoView来滚动到特定项,但它会尽可能少地滚动以使该项显示。
如何使其滚动到ListView顶部以展示所需的项?
我考虑过调用两次ScrollIntoView,一次是想要置于顶部的项,另一次是最后显示的项,但我不知道如何找到最后显示的项。
2个回答

18
我们可以通过获取ListView的ControlTemplate中存在的ScrollViewer来实现这一点。如果您可以访问ScrollViewer,则会公开很多不同的滚动方法。
首先,我们可以创建一个ListView,然后将此效果添加到其中:
<ListView ItemsSource="{Binding Percents}"
      SelectionChanged="OnSelectionChanged"
      x:Name="uiListView"/>


public List<int> Percents { get; set; }

public Window1()
{
    InitializeComponent();

    Percents = new List<int>();
    for (int i = 1; i <= 100; i++)
    {
        Percents.Add(i);
    }
    this.DataContext = this;
}

我们还需要一些东西,可以用来从ListView中获取ScrollViewer。我以前使用过类似的东西来处理自定义滚动条,在这里也可以使用它。
public static DependencyObject GetScrollViewer(DependencyObject o)
{
    if (o is ScrollViewer)
    { return o; }

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
    {
        var child = VisualTreeHelper.GetChild(o, i);

        var result = GetScrollViewer(child);
        if (result == null)
        {
            continue;
        }
        else
        {
            return result;
        }
    }

    return null;
}

现在,我们只需要处理SelectionChanged事件。因为我们正在尝试将项目滚动到列表顶部,所以最好的选择是滚动到底部,然后重新向上滚动到所选项目。正如您所说,ScrollIntoView将滚动直到项目可见,所以一旦所选项目向上滚动到达顶部,它将停止,留下我们所选的项目在列表顶部。
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;
    scrollViewer.ScrollToBottom();

    uiListView.ScrollIntoView(e.AddedItems[0]);
}

1
注意,如果您正在使用WPF扩展工具包,您可以通过一行代码获取ScrollViewer:VisualTreeHelperEx.FindDescendantByType<ScrollViewer>(YourListView); - Mr. Bungle
不错 @Mr.Bungle!只是补充一下:VisualTreeHelperEx在Xceed.Wpf.Toolkit.Core.Utilities命名空间中。得深挖一下才找到它;-) - GBU

4

这是对@rmoore答案的一种替代方案,避免了滚动到底部。同时请注意,这仅在SelectionMode=Single的情况下有用。

如果ScrollViewer.CanContentScroll=True,则ScrollViewer可以直接滚动到SelectedIndex

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;      
    scrollViewer.ScrollToVerticalOffset(listView.SelectedIndex);
}

如果ScrollViewer.CanContentScroll=False,则需要一些额外的XAML:

<ListView ScrollViewer.CanContentScroll="False" ItemsSource="{Binding Percents}" x:Name="uiListView">
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <EventSetter Event="Selected" Handler="OnSelected"/>
        </Style>
     </ListView.ItemContainerStyle>
</ListView>

ScrollViewer 可以将滚动位置移动到 ListViewItem 顶部的垂直偏移量。

private void OnSelected(object sender, RoutedEventArgs e)
{
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;      

    ListViewItem listViewItem = (ListViewItem)e.Source;
    Point offset = listViewItem.TranslatePoint(new Point(), scrollViewer);
    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset.Y);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接