wpf 为什么 ListView.ScrollIntoView 不工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16942580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't ListView.ScrollIntoView ever work?
提问by jay_t55
I am trying to scroll into view so that the very last item in a vertical listivew is always showing, but ListView.ScrollIntoView() never works.
我试图滚动到视图中,以便始终显示垂直列表中的最后一项,但 ListView.ScrollIntoView() 永远不会工作。
I have tried:
我试过了:
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);
}
I have also tried:
我也试过:
ActivityList.ScrollIntoView(ActivityList.Items.Count), and ActivityList.ScrollIntoView(ActivityList.Items.Count + 1);but nothing is working.
ActivityList.ScrollIntoView(ActivityList.Items.Count),ActivityList.ScrollIntoView(ActivityList.Items.Count + 1);但没有任何效果。
Please help. This is really annoying. And the documentation isn't very helpfulin this case.
请帮忙。这真的很烦人。在这种情况下,文档并不是很有帮助。
回答by keyboardP
You're passing in the index when the method expects the item object. Try this to scroll to the selected item.
当该方法需要 item 对象时,您正在传入索引。试试这个滚动到所选项目。
ActivityList.ScrollIntoView(ActivityList.SelectedItem);
If you want to scroll to the last item, you can use this
如果你想滚动到最后一个项目,你可以使用这个
ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);
回答by Gábor
It's got something to do with the internal list representation, namely, the items are not yet in place when you call the ScrollIntoView().After many attempts, this is what I finally came up with and this seems to work: attach twohandlers to every ListBox/ListView:
它与内部列表表示有关,即,当您调用ScrollIntoView().后,项目尚未就位经过多次尝试,这就是我最终想出的,这似乎有效:将两个处理程序附加到每个ListBox/ListView:
<ListBox x:Name="YourList" ... Loaded="YourList_Loaded" SelectionChanged="YourList_SelectionChanged">
and
和
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);
}
The second handler you can't do without. You can't call ScrollIntoView()immediately after you set the selected item, it's not yet ready. You have to allow the list to inform you when it has actually changed the item. The first handler depends on the circumstances, if you have problems with the selection showing up after the initial loading of the list contents, you might need it, too.
你离不开的第二个处理程序。ScrollIntoView()设置好所选项目后不能立即调用,它还没有准备好。您必须允许列表在实际更改项目时通知您。第一个处理程序取决于具体情况,如果您在初始加载列表内容后出现的选择出现问题,您可能也需要它。
回答by hug
The problem with ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);and similiar "solutions", at least from what I'm experiencing, is that when the ListBox contains the same item more than once, it jumps to the first it finds, i.e. lowest index. So, it doesn't care about the index of the item you input, it just looks for that item and picks the first.
ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);至少从我遇到的情况来看,类似“解决方案”的问题是,当 ListBox 多次包含相同的项目时,它会跳转到它找到的第一个,即最低索引。因此,它不关心您输入的项目的索引,它只查找该项目并选择第一个。
I haven't yet found a solution to this, but the approach I'm taking right now is to Insert instead of Add items. In the original posters case I think that would result in:
我还没有找到解决方案,但我现在采取的方法是插入而不是添加项目。在最初的海报案例中,我认为这会导致:
activities.Insert(0, new Activities()
{
Time = DateTime.Now,
Message = message
});
or possibly:
或者可能:
ActivityList.Items.Insert(0, new Activities()
{
Time = DateTime.Now,
Message = message
});
Which causes every new entry to be inserted in the top, and thus ScrollIntoView doesn't even need to be called.
这会导致每个新条目都插入顶部,因此甚至不需要调用 ScrollIntoView。
回答by ck84vi
Its an old post but since none of the answers here worked for my case I want to add my implementation. I found the solution here: [https://social.msdn.microsoft.com/Forums/vstudio/en-US/8a745550-4360-4b53-85f5-032f8f46e2cc/listview-scrollintoview-not-working-with-a-observablecollection?forum=wpf][1]
它是一篇旧帖子,但由于这里的答案都不适用于我的案例,因此我想添加我的实现。我在这里找到了解决方案:[ https://social.msdn.microsoft.com/Forums/vstudio/en-US/8a745550-4360-4b53-85f5-032f8f46e2cc/listview-scrollintoview-not-working-with-a-observablecollection ?论坛=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;
}
For me it works perfect.
对我来说它完美无缺。
回答by SWeko
You are assigning the index of the item, and the list box expects the item itself. Try something like this:
您正在分配项目的索引,列表框需要项目本身。尝试这样的事情:
var activity = new Activities()
{
Time = DateTime.Now,
Message = message
};
activities.Add(activity);
ActivityList.ItemsSource = activities;
ActivityList.ScrollIntoView(activity);
回答by Alex
The problem I faced was similar. I was adding programatically to a ListBox and needed the last item added to be visible. After tying various methods I found the following to be the simplest and the best
我面临的问题是相似的。我以编程方式添加到 ListBox 并需要添加的最后一个项目可见。捆绑了各种方法后,我发现以下是最简单和最好的
lstbox.Items.MoveCurrentToLast();
lstbox.ScrollIntoView(lstbox.Items.CurrentItem);
回答by Paul
This is an old post but I had the same problem in a Windows Store app and found the following worked:
这是一篇旧帖子,但我在 Windows Store 应用程序中遇到了同样的问题,发现以下方法有效:
private void PagesListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
pageListView.UpdateLayout();
pageListView.ScrollIntoView(pageListView.SelectedItem);
}
Cheers, Paul
干杯,保罗
回答by Robert Nol
Just call method UpdateLayout...
只需调用方法 UpdateLayout ...
UpdateLayout();
ActivityList.ScrollIntoView(ActivityList.Items[ActivityList.Items.Count - 1]);
This will work...
这将工作...
Or more easier way...just compile app :) and it will work without UpdateLayot()
或者更简单的方法......只需编译应用程序:)它就可以在没有 UpdateLayot() 的情况下工作
回答by ThePennyDrops
I am not sure if this topic is still of interest, but I could not get the above options to work on my LISTBOX. I read somewhere that unequal item sizes also stopped the scroll working. I did get the below Powershell code to work; the 'UpdateLayout()' seemed to be vital:
我不确定这个话题是否仍然令人感兴趣,但我无法让上述选项在我的 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 -----
回答by Adephx
In accordance with what keyboardPstated on Jun 5 '13 at 14:37 here: https://stackoverflow.com/a/16942650/2717521
根据keyboardP于 2013 年 6 月 5 日 14:37 在这里声明的内容:https: //stackoverflow.com/a/16942650/2717521
if that still doesn't work, try calling ActivityList.UpdateLayout(); just before the ScrollIntoView method.
如果仍然不起作用,请尝试调用 ActivityList.UpdateLayout(); 就在 ScrollIntoView 方法之前。
I had a simmilar problem between what I initially thought, identical DataGrids. First one would ScrollIntoView without any issues, second one refused to do so no matter what, unless I triggered UpdateLayout. It turns out that I was also grouping the second DataGrid:
我最初认为相同的 DataGrids 之间有一个类似的问题。第一个将 ScrollIntoView 没有任何问题,第二个无论如何都拒绝这样做,除非我触发了 UpdateLayout。事实证明,我也在对第二个 DataGrid 进行分组:
mycollection.GroupDescriptions.Clear();
mycollection.GroupDescriptions.Add(new PropertyGroupDescription("PART"));
datagrid_parts.ItemsSource = mycollection.View;
Apparently if your DataGrid is grouping, the ScrollViewer can not get correct "visual" space, because some visible areas stay inside Group as GroupItem. Refference: 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
显然,如果您的 DataGrid 正在分组,则 ScrollViewer 无法获得正确的“视觉”空间,因为某些可见区域作为 GroupItem 保留在 Group 内。参考:https://social.msdn.microsoft.com/Forums/vstudio/en-US/b809f5ae-08e7-415f-9e86-fc0086cb49e7/datagrid-scrollintoview-does-not-bring-given-item-into-view-何时使用虚拟化和分组?论坛=wpf

