C# WinForms ListView,在重新加载时记住滚动位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/626315/
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
WinForms ListView, Remembering Scrolled Location on Reload
提问by djdd87
I've got a list view that I'm populating with 8 columns of user data. The user has the option to enable auto refreshing, which causes the ListView to be cleared and repopulated with the latest data from the database.
我有一个列表视图,其中填充了 8 列用户数据。用户可以选择启用自动刷新,这会导致 ListView 被清除并使用数据库中的最新数据重新填充。
The problem is that when the items are cleared and repopulated, the visible area jumps back to the top of the list. So if I'm looking at item 1000 of 2000, it's very inconvenient to get back to that item.
问题是当项目被清除并重新填充时,可见区域会跳回到列表的顶部。因此,如果我正在查看 2000 年中的第 1000 项,返回到该项目非常不方便。
Basically, what I'm asking is, how do I get the current scroll distances (x and y) and then restore them?
基本上,我要问的是,如何获得当前的滚动距离(x 和 y)然后恢复它们?
采纳答案by Grzenio
I had the same problem with a while ago and I ended up implementing an algorithm to compare the model with the list, so I only added/removed elements that had changed. This way if there were no massive changes the list didn't jump to the beginning. And the main thing I wanted to achieve was the efficiency (so that the list doesn't blink).
不久前我遇到了同样的问题,我最终实现了一种算法来将模型与列表进行比较,因此我只添加/删除了已更改的元素。这样,如果没有大量更改,列表就不会跳到开头。我想实现的主要目标是效率(这样列表不会闪烁)。
回答by Chris Doggett
Look at the ListView.TopItem property. It has an index, which should contain its position in the list. Find that index in the new list, and set TopItem to that item, and it should do the scrolling automatically.
查看 ListView.TopItem 属性。它有一个索引,它应该包含它在列表中的位置。在新列表中找到该索引,并将 TopItem 设置为该项目,它应该自动进行滚动。
回答by Aleris
Unfortunately you will need to use some interop to scroll to the exact position in the ListView. Use GetScrollInfowinapi function to get the existing scroll position and SendMessageto scroll to the position.
不幸的是,您需要使用一些互操作来滚动到 ListView 中的确切位置。使用GetScrollInfowinapi 函数获取现有滚动位置并使用SendMessage滚动到该位置。
There in an article on CodeProject named Scrolling to a group with a ListViewthat might guide you to the solution.
在一篇关于 CodeProject 的文章中,名为Scrolling to a group with a ListView可能会指导您找到解决方案。
回答by TheAgent
I just wanted to provide some information for those who desperately try to use the buggy ListView.TopItem property:
我只是想为那些拼命尝试使用有问题的 ListView.TopItem 属性的人提供一些信息:
- You MUST set the TopItem property AFTER calling ListView.EndUpdate
- The items of the ListView control MUST have their Text property set to something other than String.Empty, or the property won't work.
- Setting the ListView.TopItem throws null reference exceptions intermittently. Always keep this line of code inside a Try...Catch block.
- 您必须在调用 ListView.EndUpdate 后设置 TopItem 属性
- ListView 控件的项必须将它们的 Text 属性设置为 String.Empty 以外的值,否则该属性将不起作用。
- 设置 ListView.TopItem 会间歇性地抛出空引用异常。始终将这行代码保存在 Try...Catch 块中。
Of course, this will cause the ListView's scrollbar to jump to 0 and back to the location of the top item, which is annoying. Please update this question if you find a workaround to this problem.
当然,这样会导致ListView的滚动条跳到0,又回到最上面item的位置,很烦。如果您找到解决此问题的方法,请更新此问题。
回答by Wildcatter
I was having sort-of the same problem. I have a listView that I populate every 1/2 sec and when I set the TopItem to an ListItem whose index > visible items, then the list jumped between the topItem and back 2 spots.
我遇到了同样的问题。我有一个 listView,每 1/2 秒填充一次,当我将 TopItem 设置为索引 > 可见项的 ListItem 时,列表在 topItem 和后 2 个点之间跳转。
So, to correct the problem, I set the TopIterm AFTER the call to EndUpdate.
因此,为了纠正这个问题,我在调用 EndUpdate 之后设置了 TopIterm。
lvB.EndUpdate();
lvI.EndUpdate();
lvR.EndUpdate();
if (lstEntryInts.Items.Count > 0)
lstEntryInts.TopItem = lstEntryInts.Items[iTopVisIdx];
if (lstEntryBools.Items.Count > 0)
lstEntryBools.TopItem = lstEntryBools.Items[iTopVisIdx];
if (lstEntryReals.Items.Count > 0)
lstEntryReals.TopItem = lstEntryReals.Items[iTopVisIdx];?
回答by John M
My solution to maintaining scroll position:
我保持滚动位置的解决方案:
Form level variable:
表单级别变量:
private static int scrollSpot = 0;
Inside listview refresh (ie Timer,button) to store the current spot:
内部列表视图刷新(即定时器,按钮)以存储当前位置:
scrollSpot = this.listView1.TopItem.Index;
refreshTheForm();
Inside refreshTheForm method to show the stored spot (put at very end of method):
在 refreshTheForm 方法中显示存储的点(放在方法的最后):
if (scrollSpot <= 1)
{
listView1.Items[scrollSpot].Selected = true;
}
else
{
listView1.Items[scrollSpot - 2].Selected = true;
}
listView1.TopItem = listView1.SelectedItems[0];
回答by Lutz Kretzschmar
The TopItemIndex property on ListView is what you are looking for, however it has some confirmed bugs that should have been addressed in VS2010 release.. not sure (haven't checked).
ListView 上的 TopItemIndex 属性是您要查找的内容,但是它有一些已确认的错误,这些错误本应在 VS2010 版本中解决。不确定(尚未检查)。
Anyway, my workaround for making this work is to do this:
无论如何,我完成这项工作的解决方法是这样做:
listViewOutput.TopItemIndex = outputList.Count - 1;
listViewOutput.TopItemIndex = myNewTopItemIndex;
For some reason setting it directly does not update it, but setting it to the last item and then the one I want works reliably for me.
出于某种原因,直接设置它不会更新它,而是将它设置为最后一项,然后我想要的那个对我来说可靠地工作。
回答by Dave Lucre
I used the following successfully:
我成功地使用了以下内容:
int topItemIndex = 0;
try
{
topItemIndex = listView1.TopItem.Index;
}
catch (Exception ex)
{ }
listView1.BeginUpdate();
listView1.Items.Clear();
//CODE TO FILL LISTVIEW GOES HERE
listView1.EndUpdate();
try
{
listView1.TopItem = listView1.Items[topItemIndex];
}
catch (Exception ex)
{ }
回答by Conrad de Wet
In my tests, you did not even need the TopItem, although I used a int to save the selected item. Also TopItem throws an exception if you are using View.Tile or View.LargeIcon.
在我的测试中,您甚至不需要 TopItem,尽管我使用 int 来保存所选项目。如果您使用 View.Tile 或 View.LargeIcon,TopItem 也会抛出异常。
This code does not move the scroll bars:
此代码不会移动滚动条:
listView1.BeginUpdate();
listView1.Items.Clear();
// loop through your add routine
listView1.Items.Add(lvi);
listView1.EndUpdate();