为什么ListView.ScrollIntoView不起作用?

时间:2013-06-05 14:27:14

标签: c# .net wpf xaml

我正在尝试滚动到视图中,以便垂直listivew中的最后一项始终显示,但ListView.ScrollIntoView()永远不会起作用。

我试过了:

button1_Click(object sender, EventArgs e)
{

            activities.Add(new Activities()
            {
                Time = DateTime.Now,
                Message = message
            });

            ActivityList.ItemsSource = activities;

            // Go to bottom of ListView.
            ActivityList.SelectedIndex = ActivityList.Items.Count;
            ActivityList.ScrollIntoView(ActivityList.SelectedIndex);
}

我也尝试过:

ActivityList.ScrollIntoView(ActivityList.Items.Count)ActivityList.ScrollIntoView(ActivityList.Items.Count + 1);但没有任何效果。

请帮忙。这真的很烦人。在这种情况下,文档isn't very helpful

11 个答案:

答案 0 :(得分:14)

当方法需要item对象时,您将传入索引。尝试此操作滚动到所选项目。

ActivityList.ScrollIntoView(ActivityList.SelectedItem);

如果要滚动到最后一项,可以使用此

ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);

答案 1 :(得分:8)

它与内部列表表示有关,即当您调用ScrollIntoView().时,项目尚未到位。经过多次尝试后,这就是我最终想出来的内容似乎工作:将两个处理程序附加到每个ListBox/ListView:

<ListBox x:Name="YourList" ... Loaded="YourList_Loaded" SelectionChanged="YourList_SelectionChanged">

void YourList_Loaded(object sender, RoutedEventArgs e) {
  if (YourList.SelectedItem != null)
    YourList.ScrollIntoView(YourList.SelectedItem);
}

void YourList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
  if (YourList.SelectedItem != null)
    YourList.ScrollIntoView(YourList.SelectedItem);
}

你不能做的第二个处理程序。设置所选项目后,您无法立即致电ScrollIntoView(),但尚未准备就绪。您必须允许列表在实际更改项目时通知您。第一个处理程序取决于具体情况,如果在初始加载列表内容后出现选择问题,您可能也需要它。

答案 2 :(得分:3)

ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);的问题 和类似的“解决方案”,至少从我遇到的情况来看,当ListBox不止一次包含相同的项目时,它会跳转到它找到的第一个,即最低索引。因此,它不关心您输入的项目的索引,它只是查找该项目并选择第一项。

我还没有找到解决方案,但我现在采取的方法是插入而不是添加项目。在原始的海报案例中,我认为这将导致:

activities.Insert(0, new Activities()
        {
            Time = DateTime.Now,
            Message = message
        });

或可能:

ActivityList.Items.Insert(0, new Activities()
        {
            Time = DateTime.Now,
            Message = message
        });

这导致每个新条目都插入到顶部,因此甚至不需要调用ScrollIntoView。

答案 3 :(得分:1)

您正在分配项目的索引,列表框需要项目本身。 尝试这样的事情:

 var activity = new Activities()
        {
            Time = DateTime.Now,
            Message = message
        };

 activities.Add(activity);

 ActivityList.ItemsSource = activities;
 ActivityList.ScrollIntoView(activity);

答案 4 :(得分:1)

这是一篇旧帖子,但由于这里没有任何答案适用于我的案例,我想添加我的实现。 我在这里找到了解决方案:[https://social.msdn.microsoft.com/Forums/vstudio/en-US/8a745550-4360-4b53-85f5-032f8f46e2cc/listview-scrollintoview-not-working-with-a-observablecollection?forum=wpf][1]

((INotifyCollectionChanged)lvLogs.Items).CollectionChanged += ListView_CollectionChanged;

private void ListView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    ScrollToEnd(this.lvLogs);
}

private void ListView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if ((e.Action == NotifyCollectionChangedAction.Add) && (e.NewItems != null))
            {
                try 
                {
                    ScrollToEnd(this.lvLogs);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), "Error updating list view", MessageBoxButton.OK, MessageBoxImage.Error);
                }

            }
        }

public void ScrollToEnd(ListView _ListView)
{
    ScrollViewer _ScrollViewer = GetDescendantByType(_ListView, typeof(ScrollViewer)) as ScrollViewer;
    _ScrollViewer.ScrollToEnd();
}

public Visual GetDescendantByType(Visual element, Type type)
{
    if (element == null) return null;
    if (element.GetType() == type) return element;
    Visual foundElement = null;
    if (element is FrameworkElement)
    {
        (element as FrameworkElement).ApplyTemplate();
    }
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
    {
        Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
        foundElement = GetDescendantByType(visual, type);
        if (foundElement != null)
            break;
    }
    return foundElement;
}

对我来说,它很完美。

答案 5 :(得分:0)

我遇到的问题与此类似。我正在以编程方式添加到ListBox,并且需要添加的最后一项是可见的。在绑定各种方法后,我发现以下是最简单和最好的

lstbox.Items.MoveCurrentToLast();
lstbox.ScrollIntoView(lstbox.Items.CurrentItem);

答案 6 :(得分:0)

这是一篇旧帖子,但我在Windows应用商店应用中遇到了同样的问题,发现以下情况有效:

    private void PagesListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        pageListView.UpdateLayout();
        pageListView.ScrollIntoView(pageListView.SelectedItem);
    }

干杯, 保罗

答案 7 :(得分:0)

只需调用方法UpdateLayout ...

UpdateLayout();
ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);

这会有用......

或者更简单的方法...只需编译应用程序:)它将在没有UpdateLayot()

的情况下运行

答案 8 :(得分:0)

我不确定该主题是否仍然令人感兴趣,但是我无法使用上述选项在我的LISTBOX上使用。 我在某处读到不一样的项目大小也停止了滚动工作。 我确实获得了下面的Powershell代码; “ UpdateLayout()”似乎至关重要:

$zItemsCount = $ListBox.Items.Count - 1
Write-Host -ForegroundColor Cyan "ListBox Items Count - 1:" $zItemsCount
(0..$zItemsCount) | ForEach-Object {
  $ListBox.SelectedIndex = $_
  $ListBox.UpdateLayout()
  $ListBox.ScrollIntoView($ListBox.SelectedItem)
  }#-EndOf: each item -----

答案 9 :(得分:0)

根据键盘P 在13年6月5日14:37此处声明的内容:https://stackoverflow.com/a/16942650/2717521

如果仍然不起作用,请尝试调用ActivityList.UpdateLayout();。就在ScrollIntoView方法之前。

我最初想到的是相同的DataGrid之间有一个类似的问题。第一个将ScrollIntoView毫无问题,第二个则无论如何都拒绝这样做,除非我触发了UpdateLayout。事实证明,我还在对第二个DataGrid进行分组:

        mycollection.GroupDescriptions.Clear();
        mycollection.GroupDescriptions.Add(new PropertyGroupDescription("PART"));
        datagrid_parts.ItemsSource = mycollection.View;

显然,如果您的DataGrid正在分组,则ScrollViewer无法获得正确的“可视”空间,因为某些可见区域保留在Group as GroupItem中。参考:https://social.msdn.microsoft.com/Forums/vstudio/en-US/b809f5ae-08e7-415f-9e86-fc0086cb49e7/datagrid-scrollintoview-does-not-bring-given-item-into-view-when-using-virtualization-and-grouping?forum=wpf

答案 10 :(得分:0)

发生这种情况的另一个原因是项目已被 ItemsPanel 虚拟化,默认情况下是 VirtualizingStackPanel。如果您不需要虚拟化,因为您只有相对较少的项目,那么您可以使用普通的 StackPanel 作为您的 ItemsPanel。

<ListBox>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Vertical" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ListBox>