【Winform】ListView虚拟模式与普通模式的性能对比

博客探讨了Winform中ListView控件的虚拟模式与普通模式的性能差异。虚拟模式通过RetrieveVirtualItem和CacheVirtualItems事件提高数据插入效率,适用于处理大量数据。然而,它也会增加内存消耗,特别是面对几十万条数据时。文章基于SharpDevelop 4.4和.NET Framework 4.5.1进行测试,并提供了简单的测试代码示例。

看见论坛中有人问ListView的虚拟模式是否能使用图标,当时我不知道何为虚拟模式,顿时兴趣大增,查阅各种资料后,现把成果分享一下。

ListView中属性VirtualMode,当把它设置为true时,控件不再使用Collection.Add()这种方式来添加数据,取而代之的是使用RetrieveVirtualItemCacheVirtualItems两个事件,单独使用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的图标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值