C# WinForms ListView,在重新加载时记住滚动的位置
我有一个列表视图,我正在填充8列用户数据。用户可以选择启用自动刷新,这会导致清除ListView并使用数据库中的最新数据重新填充 问题是,当项目被清除并重新填充时,可见区域会跳回列表的顶部。所以,如果我看的是2000年的第1000项,回到那一项是非常不方便的C# WinForms ListView,在重新加载时记住滚动的位置,c#,winforms,listview,.net-2.0,listviewitem,C#,Winforms,Listview,.net 2.0,Listviewitem,我有一个列表视图,我正在填充8列用户数据。用户可以选择启用自动刷新,这会导致清除ListView并使用数据库中的最新数据重新填充 问题是,当项目被清除并重新填充时,可见区域会跳回列表的顶部。所以,如果我看的是2000年的第1000项,回到那一项是非常不方便的 基本上,我要问的是,如何获得当前的滚动距离(x和y),然后恢复它们?我不久前遇到了同样的问题,我最终实现了一个算法来比较模型和列表,所以我只添加/删除了更改的元素。这样一来,如果没有重大变化,列表就不会跳到开头。我想实现的主要目标是提高效率
基本上,我要问的是,如何获得当前的滚动距离(x和y),然后恢复它们?我不久前遇到了同样的问题,我最终实现了一个算法来比较模型和列表,所以我只添加/删除了更改的元素。这样一来,如果没有重大变化,列表就不会跳到开头。我想实现的主要目标是提高效率(这样列表就不会闪烁)。查看ListView.TopItem属性。它有一个索引,它应该包含它在列表中的位置。在新列表中找到该索引,并将TopItem设置为该项,它将自动执行滚动操作。不幸的是,您需要使用一些互操作来滚动到ListView中的确切位置。使用winapi函数获取现有的滚动位置并滚动到该位置
在一篇名为CodeProject的文章中,可能会引导您找到解决方案。我只是想为那些拼命尝试使用buggy ListView.TopItem属性的人提供一些信息:
当然,这会导致ListView的滚动条跳转到0并返回到顶部项目的位置,这很烦人。如果找到解决此问题的方法,请更新此问题。我也遇到过类似的问题。我有一个listView,每1/2秒填充一次,当我将TopItem设置为其索引>可见项的ListItem时,列表在TopItem和后面2个点之间跳转 因此,为了纠正这个问题,我在调用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];
我维护滚动位置的解决方案: 表单级别变量:
private static int scrollSpot = 0;
内部listview刷新(即计时器、按钮)以存储当前点:
scrollSpot = this.listView1.TopItem.Index;
refreshTheForm();
在RefreshForm方法中显示存储的点(放在方法的末尾):
if(scrollSpotListView上的TopItemIndex属性是您要查找的,但是它有一些已确认的错误,应该在VS2010版本中解决。不确定(尚未检查)
无论如何,我的解决办法是:
listViewOutput.TopItemIndex = outputList.Count - 1;
listViewOutput.TopItemIndex = myNewTopItemIndex;
由于某些原因,直接设置它不会更新它,但将它设置为最后一项,然后设置为我想要的项对我来说是可靠的。我成功地使用了以下选项:
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)
{ }
在我的测试中,您甚至不需要TopItem,尽管我使用了int来保存所选项目。如果您使用的是View.Tile或View.LargeIcon,TopItem也会引发异常
此代码不会移动滚动条:
listView1.BeginUpdate();
listView1.Items.Clear();
// loop through your add routine
listView1.Items.Add(lvi);
listView1.EndUpdate();
这就是我所做的。我在第一个子项中添加了一个标记,然后用它来进行比较,并仅在需要时进行更新。ListView.TopItem似乎不起作用。我认为它可能与排序有关,所以我禁用了它,但当我将TopItem设置为一个项并在之后立即检查属性时,它没有被更改(更改到另一个项目,而不是我指定的项目)。你知道吗?我发现在分配到TopItem(即,它滚动到我请求的项目上方)时出现了一个错误,但如果我调用它两次,它就会工作。Buggy,你说?:-)它当然只在我把它放在EndUpdate之后才起作用,但它不会在没有try-catch的情况下抛出任何错误?它现在已经修复了,还是应该放try-catch?FWIW,我在WinForms属性列表中没有看到TopItemIndex:它不会与LargeIcon一起工作,抛出:“无法在LargeIcon、SmallIcon或Tile视图中获取顶部项目”。多好啊。。
listView1.BeginUpdate();
listView1.Items.Clear();
// loop through your add routine
listView1.Items.Add(lvi);
listView1.EndUpdate();