【发布时间】:2012-01-09 14:17:59
【问题描述】:
如何从 winforms 列表视图中获取可见项目?似乎没有一个直接的方法,我不愿意通过 control.clientrectangle 或其他类似于以下的 hack 来查询项目:
当我说可见时,我的意思是项目在屏幕上可见。
【问题讨论】:
-
ListView.GetItemAt() 是正确的方法。
如何从 winforms 列表视图中获取可见项目?似乎没有一个直接的方法,我不愿意通过 control.clientrectangle 或其他类似于以下的 hack 来查询项目:
当我说可见时,我的意思是项目在屏幕上可见。
【问题讨论】:
您可以从 ListView.TopItem 进行迭代,并检查每个项目的 ListViewItem.Bounds 属性是否位于客户区域内。
Better ListView Express 是一个免费软件组件,它还具有 BottomItem 属性,因此您可以使用 for 循环轻松浏览可见项目(如果两个 TopItem 和 BottomItem 不是 null):
for (int i = betterListView.TopItem.Index; i < betterListView.BottomItem.Index; i++)
{
// your code here
}
您可以试试这个 - 它与 ListView 具有相同的界面,并且比 .NET ListView 有许多改进。
【讨论】:
使用 GetItemAt 的示例代码
看着@Hans Passants 的评论,我尝试着实际创建代码。
此代码获取顶部/底部项目。从索引位于顶部/底部索引之间的项目中取出可见项目的集合应该很容易。
对我来说,这比使用 Bounds 效果好得多,ListView 的边界似乎高于可见部分。
/// <summary>
/// Finds top/bottom visible items
/// </summary>
public static (ListViewItem, ListViewItem) GetTopBottomVisible(ListView listView)
{
ListViewItem topItem = listView.TopItem;
int lstTop = listView.Top;
int lstHeight = lstTop + listView.Height;
int lstBottom = lstHeight;
int step = lstHeight/2;
int x = listView.Left + listView.Width/2;
int y = lstTop + step;
ListViewItem bottomCandidate=null;
// iterate by interval halving
while ( step > 0 )
{
step /= 2; // halv interval
ListViewItem itm = listView.GetItemAt(x, y);
if ( itm == null )
{
// below last, move up
y -= step;
}
else if ( itm == bottomCandidate )
{
// Moving still in same item, stop here
break;
}
else
{
// above last, move down, storing candidate
bottomCandidate = itm;
y += step;
}
}
return (topItem, bottomCandidate);
}
【讨论】:
如果您正在寻找一个只为您提供可见项目列表的功能,那么没有这样的东西。你可以去 foreach 项目并检查它是否可见。 (如果我理解你的问题对吗?请给出清楚的解释)
【讨论】: