看见论坛中有人问ListView的虚拟模式是否能使用图标,当时我不知道何为虚拟模式,顿时兴趣大增,查阅各种资料后,现把成果分享一下。
ListView中属性VirtualMode,当把它设置为true时,控件不再使用Collection.Add()这种方式来添加数据,取而代之的是使用RetrieveVirtualItem和CacheVirtualItems两个事件,单独使用RetrieveVirtualItem也可以,CacheVirtualItems这个事件主要是为了方便编程人员操作缓冲集合,其参数CacheVirtualItemsEventArgs有StartIndex和EndIndex两个属性
据说DataGridView这个控件也有虚拟模式,这个我没有做测试。
虚拟模式是专门为使用海量数据编程而设计的,几千条数据感觉不明显。
优势:在虚拟模式下,数据插入的效率成倍增长。
缺点:因虚拟模式使用了一个缓冲集合,相当于一次读入所有数据,当数据量很大时,例如几万条或者几十万条数据,程序占用内存很大。可以手动释放缓存,等GC回收有点慢。
==================测试环境==================
IDE: SharpDevelop 4.4
.Net Framework 4.5.1
CPU: AMD 5000+黑盒 oc到2.7GHz
Mem: DDR2 800
===========================================
程序很简单,界面如下:
代码如下:
虚拟模式:
public partial class ListViewWithVirtualMode : Form
{
private ListViewItem[] _itemsCacheCollection;
private ImageList _imageList;
private int _nTotalRows;
public ListViewWithVirtualMode()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
void ListViewWithVirtualModeLoad(object sender, EventArgs e)
{
_imageList = new ImageList();
_imageList.Images.Add(Image.FromFile("../../Images/right.png"));
_imageList.Images.Add(Image.FromFile("../../Images/wrong.png"));
_nTotalRows = Convert.ToInt32(textBox_TotalRows.Text);
listView1.Width = 170;
listView1.View = View.SmallIcon;
listView1.SmallImageList = _imageList;
}
private void Button_GenerateColClick(object sender, EventArgs e)
{
if (listView1.Items.Count != 0)
{
_itemsCacheCollection = null;
listView1.Clear();
}
_nTotalRows = Convert.ToInt32(textBox_TotalRows.Text);
listView1.CacheVirtualItems += listView1_CacheVirtualItems;
listView1.RetrieveVirtualItem += listView1_RetrieveVirtualItem;
/*
* 这里有两种设置虚拟缓冲区的大小
* 1 listView1.VirtualListSize = TextBox.Text;
* 2 listView1.VirtualListSize = TextBox.Text + ?
* ? = 随便一个数值,比如1000
* listView1.EnsureVisible(listView1.Items.Count - 1);
* EnsureVisible作用为可视的条数,如果方法2不设置这个函数
* 当拖动ListView到最后时会报索引越界的错误
*/
listView1.VirtualListSize = _nTotalRows;
listView1.VirtualMode = true;
}
private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
if (_itemsCacheCollection != null)
{
e.Item = _itemsCacheCollection[e.ItemIndex];
}
else
{
e.Item = new ListViewItem(e.ItemIndex.ToString());
}
}
void listView1_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
{
if (_itemsCacheCollection != null)
return;
_itemsCacheCollection = new ListViewItem[_nTotalRows];
if (checkBox_Icons.Checked)
{
for (int i = 0; i < _nTotalRows; i++)
{
if (i % 2 == 0)
{
_itemsCacheCollection[i] = new ListViewItem((i + 1).ToString(), 0);
}
else
{
_itemsCacheCollection[i] = new ListViewItem((i + 1).ToString(), 1);
}
}
}
else
{
for (int i = 0; i < _nTotalRows; i++)
{
_itemsCacheCollection[i] = new ListViewItem((i + 1).ToString());
}
}
}
}
普通模式:
public partial class ListViewWithoutVirtualMode : Form
{
private ListViewItem[] _itemsCacheCollection;
private ImageList _imageListSmall;
public ListViewWithoutVirtualMode()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
void ListViewWithoutVirtualModeLoad(object sender, EventArgs e)
{
_imageListSmall = new ImageList();
_imageListSmall.Images.Add(Image.FromFile("../../Images/right.png"));
_imageListSmall.Images.Add(Image.FromFile("../../Images/wrong.png"));
listView1.SmallImageList = _imageListSmall;
}
void Btn_GenerateClick(object sender, EventArgs e)
{
_itemsCacheCollection = null;
listView1.Clear();
var rowCount = Convert.ToInt32(textBox_RowTotal.Text);
_itemsCacheCollection = new ListViewItem[rowCount];
if (!checkBox_PictureCol.Checked)
{
for (int i = 0; i < rowCount; i++)
{
_itemsCacheCollection[i] = new ListViewItem("item" + (i + 1).ToString());
}
}
else
{
for (int i = 0; i < rowCount; i++)
{
if (i % 2 == 0)
{
_itemsCacheCollection[i] = new ListViewItem("item" + (i + 1).ToString(), 0);
}
else
{
_itemsCacheCollection[i] = new ListViewItem("item" + (i + 1).ToString(), 1);
}
}
}
listView1.Items.AddRange(_itemsCacheCollection);
}
}测试结果:测试程序中开启虚拟模式5万条数据插入没感觉程序有卡顿现象,使用默认的普通模式插入1000条数据有明显卡顿现象。两种模式中均含有16x16的图标。
博客探讨了Winform中ListView控件的虚拟模式与普通模式的性能差异。虚拟模式通过RetrieveVirtualItem和CacheVirtualItems事件提高数据插入效率,适用于处理大量数据。然而,它也会增加内存消耗,特别是面对几十万条数据时。文章基于SharpDevelop 4.4和.NET Framework 4.5.1进行测试,并提供了简单的测试代码示例。

9763

被折叠的 条评论
为什么被折叠?



