最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
WinForm ListView 大数据提高加载速度的方法 虚拟模式加载
时间:2022-06-25 08:33:36 编辑:袖梨 来源:一聚教程网
将VirtualMode 属性设置为 true 会将 ListView 置于虚拟模式。控件不再使用Collection.Add()这种方式来添加数据,取而代之的是使用RetrieveVirtualItem(Occurs when the ListView is in virtual mode and requires a ListViewItem.)和CacheVirtualItems两个事件,单独使用RetrieveVirtualItem也可以,CacheVirtualItems这个事件主要是为了方便编程人员操作缓冲集合,其参数CacheVirtualItemsEventArgs有StartIndex和EndIndex两个属性在虚拟模式下。
在虚拟模式下,从缓冲之中获取所需的数据进行加载,性能会有很大提高。 在其他情况下,可能需要经常重新计算 ListViewItem 对象的值,对整个集合进行此操作将产生不可接受的性能。
示例代码:
using System; using System.Collections.Generic; using System.Windows.Forms; namespace WinFormTest { public partial class Form1 : Form { private ListmyCache; public Form1() { InitializeComponent(); myCache = new List (); } private void Form1_Load(object sender, EventArgs e) { listView1.View = View.Details; listView1.VirtualMode = true; listView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(listView1_RetrieveVirtualItem); } void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) { if (myCache != null ) { e.Item = myCache[e.ItemIndex]; } else { //A cache miss, so create a new ListViewItem and pass it back. int x = e.ItemIndex * e.ItemIndex; e.Item = new ListViewItem(x.ToString()); } } private void button1_Click(object sender, EventArgs e) { List list = GetStudentList(); foreach (var item in list) { ListViewItem listViewItem = new ListViewItem(); listViewItem.SubItems[0].Text = item.Name; listViewItem.SubItems.Add(item.Sex); myCache.Add(listViewItem); } listView1.VirtualListSize = myCache.Count; } private List GetStudentList() { List list = new List (); for (int i = 0; i < 2000; i++) { Student stu = new Student { Name = "student" + i, Sex = "男" }; list.Add(stu); } return list; } private void button2_Click(object sender, EventArgs e) { ListViewItem listItem = new ListViewItem(); listItem.SubItems[0].Text = "女"; listItem.SubItems.Add("哈哈"); myCache.Add(listItem); listView1.VirtualListSize = myCache.Count; listView1.Invalidate(); } } public class Student { public string Sex { get; set; } public string Name { get; set; } } }
总结
(1)必须设置VirtualMode为true并设置VirtualListSize大小
(2)绑定该事件RetrieveVirtualItem
(3)如果中间更新了数据需要重新设置VirtualListSize,并调用Invalidate()方法
(4)禁用selectedItem,在该模式下使用selectedItem将产生异常,可以用下面方法代替
private ListFindSelectedAll() { List r = new List (); foreach (int item in listView1.SelectedIndices) { r.Add(bufferItems[item]); } return r; }
WinForm ListView不分页加载大量数据
WinForm的ListView在加载大量数据时会出现闪烁的问题,同时数据加载很慢。如果你的列表中有超过千条的数据且不做特殊处理还是用普通的ListView.Items.Add(),估计你的用户得抱怨了。
下面说下解决方法:
1、使用listView1.Items.AddRange()代替Add
这种方法需要先将数据放入一个缓存数组中,然后调用AddRange一次性加入ListView中,同时可以用一个计数器记录一次性加入缓存的数量,如下:
listView1.Items.Clear();
if (vList.Count > 0)
{
int indexI = 0;
List
foreach (var item in vList)
{
ListViewItem li = new ListViewItem();
li.ImageIndex = 0;
li.SubItems[0].Text = item.Name;
li.Tag = item;
li.ForeColor = item.Status == 0 ? Color.Green : Color.Red;
listBuffer.Add(li);
if (indexI++ % 1000 == 0)
{
listView1.Items.AddRange(listBuffer.ToArray());
listBuffer.Clear();
}
if (indexI % 50 == 0)
{
Application.DoEvents();
}
}
listView1.Items.AddRange(listBuffer.ToArray());
}
这样可以减少ListView闪烁的次数,数据量不是很大时有效果。
2、自定义ListView类
下面这个类在网上广为流传,虽然解决了ListView闪烁的问题,但是在打开速度上和原来没什么区别,同时带来一个问题就是如果程序切换到别的ListView上,数据还会继续忘原来的ListView中添加,直到数据全面添加完成。
public class ListViewLargeData : System.Windows.Forms.ListView
{
public ListViewLargeData()
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
}
protected override void OnNotifyMessage(Message m)
{
if (m.Msg != 0x14)
{
base.OnNotifyMessage(m);
}
}
}
3、开启ListView的VirtualMode模式
此方式也是本文重点推荐的方式,可以实现不闪烁效果,而且打开速度很快。往往好的效果带来的问题是代码较为复杂,具体写法可以看官方示例http://msdn.microsoft.com/zh-cn/library/system.windows.forms.listview.virtualmode.aspx,下面说下需要注意的几点:
(1)必须设置VirtualMode为true并设置VirtualListSize大小
listView1.VirtualMode = true;
listView1.VirtualListSize = bufferItems.Count;
listView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(listView_RetrieveVirtualItem);
(2)绑定该事件为ListView计算Item
void listView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
e.Item = m_hListViewItems[e.ItemIndex];
}
(3)如果中间更新了数据需要重新设置VirtualListSize,并调用Invalidate()方法(此方法并非必须请高手指点)。
listView1.VirtualListSize = bufferItems.Count;
listView1.Invalidate();
(4)禁用selectedItem,在该模式下使用selectedItem将产生异常,可以用下面方法代替
private List
{
List
foreach (int item in listView1.SelectedIndices)
{
r.Add(bufferItems[item]);
}
return r;
}