listview虚模式下的问题

哨子 2010-06-04 09:46:33
处在虚模式下,似乎要更改它的checked属性,不像正常情况下容易,必须得双击,而且得很久才能显示出来,不知道怎么回事,有没有办法,让点击了复选框就实时改变它的项的选择状态?
...全文
346 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
哨子 2010-06-10
  • 打赏
  • 举报
回复
二楼这个答案网上到处都是……
自己已经搞定。
listView在虚模式下再点了复选框并不实时更新状态。需要一个
ListView1.Refresh();
  • 打赏
  • 举报
回复
很详细... jf啦
INTTNY 2010-06-05
  • 打赏
  • 举报
回复
第一次看到使用ListView的VirtureMode,学习学习
皇城龙三 2010-06-04
  • 打赏
  • 举报
回复
带复选框的虚拟ListView控件(转载)


原文作者:alphons
原文链接:http://www.codeproject.com/KB/miscctrl/ListViewVirtualMode.aspx
发表时间:2007年5月23日
特别说明:此为编译文章,仅供参考。如有疑问,或需下载文章所附源代码,请查看原文链接。

当要处理大量的项目时,使用虚拟ListView控件是最快速的途径。请特别注意如何使项目包含复选框。



简介

使用ListView控件载入大量项目时速度很慢。.NET 2.0的ListView控件已包含虚拟模式(VirtualMode)。使用少量的代码,就可以明显提升处理速度。请特别注意如何使用复选框。


背景知识

要使ListView控件进入虚拟模式,需要完成两项工作。设置控件的某些属性,然后编制一个事件处理程序,以“获取”虚拟项目。

void listView_RetrieveVirtualItem(object sender,
RetrieveVirtualItemEventArgs e)
{
// e 包含 ItemIndex
e.Item = listViewItem;
}
....
void SetupListview(bool blnVirtual)
{
...
this.listView1.VirtualMode = true;
this.listView1.RetrieveVirtualItem +=
new RetrieveVirtualItemEventHandler(listView_RetrieveVirtualItem);
...
}



使用本文所附源代码

代码演示了一个试验框架,你可在正常模式和虚拟模式之间转换。程序还测量了载入10万个ListView项目所需的时间。为简单起见,程序使用了静态缓冲区保存ListView项目。


private ListViewItem[] lvi;
...
private void Test()
{
// 可在虚拟和正常模式之间转换
bool blnVirtual = true;

// 启用ListViewItem 缓存
int NR = 100000;

lvi = new ListViewItem[NR];
for (int intI = 0; intI < lvi.Length; intI++)
lvi[intI] = new ListViewItem(intI + " test");

// 复选某些项目,测试一下
lvi[3].Checked = true;
lvi[5].Checked = true;
lvi[12].Checked = true;
lvi[NR-2].Checked = true;
...
}



.NET 2.0 有一个好用的Stopwatch,我便使用它测试一下从缓存将项目载入ListView控件时的性能。

...
Stopwatch stopwatch = new Stopwatch();
stopwatch.Reset();
stopwatch.Start();

SetupListview(blnVirtual);

stopwatch.Stop();
this.Text = "ListView VirtualMode=" + blnVirtual +
" : "+ lvi.Length + " items in " +
stopwatch.ElapsedMilliseconds + " mS";
...



使用以下代码测试一下ListView控件在正常模式下的性能。

...
this.listView1 = new ListView();
this.listView1.Dock = DockStyle.Fill;

this.listView1.View = View.List;
this.listView1.CheckBoxes = true;

this.listView1.Items.AddRange(lvi);
...



在正常模式下,载入10万条项目需耗时约35秒(如下图)。



作为对比,本文开头所示的例图说明在虚拟模式下载入同样多项目只需15毫秒。

关注重点

使用复选框和虚拟模式会有些问题。当载入项目时,只有已选定的项目会显示出复选框,其它的项目则不显示。还有就是点击复选框没有任何反应。当双击一个项目时会显示已选定项目,不过只在项目失去焦点时才如此。这是我已经查到的问题,也可能还存在其它问题。


作为规避措施,我将ListView 控件设置为OwnerDrawing,并且编写控件的点击和双击处理程序。由于在正常模式下,ListView绘制项目的文本不存在任何问题,因此设定DrawDefault 属性为真。同时,将属性e.Item.Checked设置为true 再设为false,就可以让未选定的项目也显示复选框。


void listView_DrawItem(object sender,
DrawListViewItemEventArgs e)
{
e.DrawDefault = true;
if (!e.Item.Checked)
{
e.Item.Checked = true;
e.Item.Checked = false;
}
}


处理单击复选框事件,首先要使用GetItemAt获取鼠标点击位置的ListViewItem。如果找到有效的项目,再确定项目是否已复选。最后,使用Invalidate 重绘项目。

void listView_MouseClick(object sender, MouseEventArgs e)
{
ListView lv = (ListView)sender;
ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
if (lvi != null)
{
if (e.X < (lvi.Bounds.Left + 16))
{
lvi.Checked = !lvi.Checked;
lv.Invalidate(lvi.Bounds);
}
}
}


由于双击一个项目可以正常工作,只是绘制有问题,因此我们自己定制绘制。

void listView_MouseDoubleClick(object sender, MouseEventArgs e)
{
ListView lv = (ListView)sender;
ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
if(lvi!=null)
lv.Invalidate(lvi.Bounds);
}


使ListView 控件使用事件处理程序。

...
   //这将使速度大增!!
this.listView1.RetrieveVirtualItem +=
new RetrieveVirtualItemEventHandler(
listView_RetrieveVirtualItem);
this.listView1.VirtualListSize = lvi.Length;
this.listView1.VirtualMode = true;

// 绘制未选定项目所需的代码
this.listView1.OwnerDraw = true;
this.listView1.DrawItem +=
new DrawListViewItemEventHandler(listView_DrawItem);

// 当选定或双击时进行重绘
this.listView1.MouseClick +=
new MouseEventHandler(listView_MouseClick);
this.listView1.MouseDoubleClick +=
new MouseEventHandler(listView_MouseDoubleClick);
...



将这些组合在一起,使ListView控件在两种模式中都可工作。

void SetupListview(bool blnVirtual)
{
// 启用ListView
this.listView1 = new ListView();
this.listView1.Dock = DockStyle.Fill;

// 这是我们所需的东西!!
this.listView1.View = View.List;
this.listView1.CheckBoxes = true;

if (blnVirtual)
{
// 这将使速度大增!!
this.listView1.RetrieveVirtualItem +=
new RetrieveVirtualItemEventHandler(
listView_RetrieveVirtualItem);
this.listView1.VirtualListSize = lvi.Length;
this.listView1.VirtualMode = true;

//绘制未选定项目所需的代码
this.listView1.OwnerDraw = true;
this.listView1.DrawItem +=
new DrawListViewItemEventHandler(listView_DrawItem);

//当选定或双击时进行重绘
this.listView1.MouseClick +=
new MouseEventHandler(listView_MouseClick);
this.listView1.MouseDoubleClick +=
new MouseEventHandler(listView_MouseDoubleClick);
}
else
{
//另一个途径
this.listView1.Items.AddRange(lvi);
}

// 在主窗口中显示
this.Controls.Add(this.listView1);
}

110,566

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧