项目背景:
在Winform的ListView中需要一次加载2000条数据,刚开始没有多想,直接使用线程,在线程中调用
listView.Items.Add(newItems);
测试数据量较小时,未发现问题,等到集成测试时加较大数据测试,发现会卡在加载。
///定义加载委托
public delegate void ShowTags(List<ListViewItem> input);
///定义List
private List<ListViewItem> lviList = new List<ListViewItem>();
///委托实现函数
private void AddAllItem(List<ListViewItem> itemsAll)
{
if (LogList.InvokeRequired)
{
ShowTags_myInvoke = new ShowTags(AddAllItem);
this.Invoke(_myInvoke, new object[] { itemsAll });
}
else
{
LogList.Items.AddRange(itemsAll.ToArray());
}
}
///线程中的处理
void ThreadFunc()
{
string sortOrderStr = "tagId ASC";
int i = 0;
DataRow[] tempRowArray = dt.Select("serverName='" + serverName + "'", sortOrderStr);
if(tempRowArray != null)
{
int length = tempRowArray.Length;
foreach (DataRow dr in tempRowArray)
{
...
string[] addStr = { serverName, dr["tagId"].ToString(), dr["tagName"].ToString(), dr["dataType"].ToString(), "", "", "", unitStr, descripStr };
dr["viewId"] = i;
ListViewItem item = new ListViewItem(addStr);
item.Tag = serverName;
lviList.Add(item);
}
AddAllItem(lviList);
}
查询资料,发现对于Winform的ListView有虚拟模式,用好这个模式,可以不要第三方控件也不需要分页处理。
原来ListView加载2000条真是小儿科,很多时候是要加30W条记录进去。
虽然加进去这么多记录,谁查看都不方便,但往往甲方的需求乙方不好更改。
当传统方法不好使的时候,就该使用虚拟模式了。
首先直观感受下虚拟模式,点击ListView查看属性,可以看到“VirtualListSize”和“VirtualMode”属性。默认情况下,VirtualMode为false,VirtuaListSize为0。
下面详述如何使用VirtualMode。
1. VirtualMode的核心是先定义一个List<ListViewItem> mList,该List是后续处理的基础。
2. 启用VirtualMode模式很简单
MyList.VirtualMode = true;
MyList.VirtualListSize = length;
MyList.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(MyList_RetrieveVirtualItem);
void MyList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
try
{
if (this.lviList == null || this.lviList.Count == 0)
{
return;
} e.Item = this.lviList[e.ItemIndex];
}
catch (System.Exception ex)
{
}
}
3.VirtualMode下的记录操作方法在虚拟模式下,Items 集合是禁用的,如果试图访问该集合将会导致 InvalidOperationException。CheckedItems 集合和SelectedItems 集合也是如此。如果希望检索选中项,请改用 SelectedIndices 和CheckedIndices 集合。 因为virtualMode下,ListView绑定显示几乎不花费时间。如果要想对记录进行操作,其实是对后台的List进行更新,然后再次进行绑定。
List<ListViewItem> newList = new List<ListViewItem>();
this.mList = newList;
MyList.VirtualListSize = newList.Count;
在多线程处理中,对于ListView,需要处理MyList_RetrieveVirtualItem中的异常,防止崩溃。
4.ListView虚拟模式的限制
ListView中原有的通过Column进行排序在虚拟模式下会报错,解决方法也是在后台的List进行处理。
参考文档:http://www.cnblogs.com/jasenkin/archive/2011/08/22/listview_virtual_model.html