WinForms ListView,在重新加载时记住滚动位置

发布于 2024-07-14 07:57:40 字数 207 浏览 12 评论 0原文

我有一个列表视图,其中填充了 8 列用户数据。 用户可以选择启用自动刷新,这会导致 ListView 被清除并使用数据库中的最新数据重新填充。

问题是,当清除并重新填充项目时,可见区域会跳回列表顶部。 因此,如果我正在查看 2000 项中的第 1000 项,则返回该项非常不方便。

基本上,我要问的是,如何获取当前的滚动距离(x 和 y)然后恢复它们?

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.

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.

Basically, what I'm asking is, how do I get the current scroll distances (x and y) and then restore them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

甜妞爱困 2024-07-21 07:57:40

我只是想为那些拼命尝试使用有问题的 ListView.TopItem 属性的人提供一些信息:

  1. 您必须在调用 ListView.EndUpdate 之后设置 TopItem 属性
  2. ListView 控件的项目必须将其 Text 属性设置为其他值
    不是 String.Empty,否则该属性将不起作用。
  3. 设置 ListView.TopItem 会间歇性地引发空引用异常。 始终将此行代码保留在 Try...Catch 块内。

当然,这会导致ListView的滚动条跳到0又回到最上面item的位置,这就很烦人了。 如果您找到此问题的解决方法,请更新此问题。

I just wanted to provide some information for those who desperately try to use the buggy ListView.TopItem property:

  1. You MUST set the TopItem property AFTER calling ListView.EndUpdate
  2. The items of the ListView control MUST have their Text property set to something other
    than String.Empty, or the property won't work.
  3. Setting the ListView.TopItem throws null reference exceptions intermittently. Always keep this line of code inside a Try...Catch block.

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.

神魇的王 2024-07-21 07:57:40

我成功地使用了以下内容:

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)
{ }

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)
{ }
海的爱人是光 2024-07-21 07:57:40

不久前我遇到了同样的问题,我最终实现了一种算法来将模型与列表进行比较,所以我只添加/删除了已更改的元素。 这样,如果没有发生重大变化,列表就不会跳到开头。 我想要实现的主要目标是效率(这样列表就不会闪烁)。

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).

执笏见 2024-07-21 07:57:40

ListView 上的 TopItemIndex 属性就是您正在寻找的内容,但是它有一些已确认的错误,这些错误应该在 VS2010 版本中得到解决。不确定(尚未检查)。

无论如何,我完成这项工作的解决方法是这样做:

listViewOutput.TopItemIndex = outputList.Count - 1;
listViewOutput.TopItemIndex = myNewTopItemIndex;

出于某种原因,直接设置它不会更新它,而是将其设置为最后一项,然后我想要的项目对我来说可靠地工作。

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).

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.

誰認得朕 2024-07-21 07:57:40

查看 ListView.TopItem 属性。 它有一个索引,其中应包含其在列表中的位置。 在新列表中找到该索引,并将 TopItem 设置为该项目,它应该自动滚动。

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.

提笔书几行 2024-07-21 07:57:40

不幸的是,您将需要使用一些互操作来滚动到 ListView 中的确切位置。 使用 GetScrollInfo winapi 函数获取现有的滚动位置和 SendMessage 滚动到该位置。

CodeProject 上一篇名为 Scrolling to a group with a ListView 的文章可能会指导您找到解决方案。

Unfortunately you will need to use some interop to scroll to the exact position in the ListView. Use GetScrollInfo winapi function to get the existing scroll position and SendMessage to scroll to the position.

There in an article on CodeProject named Scrolling to a group with a ListView that might guide you to the solution.

走走停停 2024-07-21 07:57:40

我维护滚动位置的解决方案:

表单级别变量:

private static int scrollSpot = 0;

在列表视图刷新(即计时器、按钮)内存储当前位置:

scrollSpot = this.listView1.TopItem.Index;
refreshTheForm();

在refreshTheForm方法内显示存储的位置(放在方法的最末尾):

if (scrollSpot <= 1)
{
     listView1.Items[scrollSpot].Selected = true;
}
else
{
     listView1.Items[scrollSpot - 2].Selected = true;
}
listView1.TopItem = listView1.SelectedItems[0]; 

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):

if (scrollSpot <= 1)
{
     listView1.Items[scrollSpot].Selected = true;
}
else
{
     listView1.Items[scrollSpot - 2].Selected = true;
}
listView1.TopItem = listView1.SelectedItems[0]; 
女皇必胜 2024-07-21 07:57:40

我遇到了同样的问题。 我有一个 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];​

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.

So, to correct the problem, I set the TopIterm AFTER the call to EndUpdate.

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];​
念三年u 2024-07-21 07:57:40

在我的测试中,尽管我使用 int 来保存所选项目,但您甚至不需要 TopItem。 如果您使用 View.Tile 或 View.LargeIcon,TopItem 也会引发异常。

此代码不会移动滚动条:

listView1.BeginUpdate();
listView1.Items.Clear();

// loop through your add routine
listView1.Items.Add(lvi);

listView1.EndUpdate();

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.

This code does not move the scroll bars:

listView1.BeginUpdate();
listView1.Items.Clear();

// loop through your add routine
listView1.Items.Add(lvi);

listView1.EndUpdate();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文