Introduction
This article and accompanying code was written to demonstrate a technique for displaying very large quantities of data in a visual control, with very little performance degradation.
Background
It is a common situation in working with large quantities of data, where this data needs to be presented to the user. Lists and trees are often used for this purpose. Many times, the programmer attempts to load one of these controls with an entire data set. The problem arises when an increasing number of items are added to these controls; memory usage increases and performance decreases to the point that this solution is no longer acceptable.
This article presents a technique to display very large data sets with no performance degradation.
This technique could easily be adapted to a variety of .NET controls, as well as other platforms, such as Java Swing controls.
Strategy for Displaying Large Quantities of Data in a ListView
The approach for this example is to have a list control that will only contain data items that are visible to the user, not the entire data set. The existing .NET ListView
component is used, coupled with a VScrollBar
, which is 'manually' adjusted to reflect the quantity of data being represented. Since the ListView
will only contain exactly the number of data items (ListViewItem
) that can be displayed, the internal vertical scroll bar should never show. Therefore, it is necessary to manage a separate slider that accurately reflects the quantity of data being represented. This control can be thought of as being a sliding window that moves up and down over a large set of data.
As ListViewItem
s move out of view, they are deleted, and as new ones come into view, they are added, so that the list only contains a maximum of the number of items that can be viewed by the user.
Pieces of the Puzzle
The HighPerformanceListView
is a new composite control that encapsulates a .NET ListView
control and a VScrollBar
control. This control can be added to the tool box and dropped onto a Form. To programmatically provide the data in a generic manner, this control uses an object implementing an IHighPerformanceListViewProvider
interface. This object supplies the supplemental functionality needed by the ListView
control to determine the column headers being displayed, and to provide ListViewItem
s that represent one item of data.
public interface IHighPerformanceListViewProvider
{
List<ColumnHeaders> { get; }
void SortDataList(int sortColumnNumber, SortOrder sortOrder);
ListViewItem ConvertDataItemToListViewItem(int dataIndex);
int DataCount { get; }
HighPerformanceListView ControllingListView { get; set; }
}
An abstract class, ListViewProviderBase
, is provided, and implements the ControllingListView
property of this interface.
Using the Code
The following code snippet demonstrates how to interact with the HighPerformanceListView
control:
listViewProvider = new ListViewExampleProvider();
highPerformanceListView.ListViewProvider = listViewProvider;
List<DataItem> dataList;
listViewProvider.DataList = dataList;
Points of Interest
Pass Through Events, Methods, and Properties
Since the HighPerformanceListView
control is a UserControl
that encapsulates a .NET ListView
, the ListView
specific events and properties were hidden. Pass-through properties, events, and methods had to be created for the user control that would pass-through information to the actual ListView
control. The pass-through items do not represent a total recreation of those exposed by the ListView
, but just enough to suffice for this example.
The pass-through items are organized in the HighPerformanceListView.PassThrough
file, which contains a partial class definition of the list view class.
Example of Pass-Through Event
public event DrawListViewColumnHeaderEventHandler DrawColumnHeader
{
add { listView.DrawColumnHeader += value; }
remove { listView.DrawColumnHeader -= value; }
}
Sliding Window
The concept of the 'sliding window' is managed in the HighPerformanceListView
by the following three variables:
private int displayStartIdx = 0;
private int rowsDisplayed = 0;
private int maxDisplayLines = 0;
Refreshing Items in the ListView
As the control is resized, columns resorted, or view scrolled, the display items contained in the ListView
need to be updated. The first attempt was made to optimize the process by either adding items coming into view, or deleting those items going out of view. This process caused unacceptable flicker.
Instead, each time items are added or deleted, the entire view is refreshed. This resulted in a vast improvement in visual performance. (See: HighPerformanceListView.RefreshListViewItems()
.)
Maintaining Multiple Selected Items Not in View
The current control does not track selected items that have gone out of view, but this could easily be added if needed.
ListView.VirtualMode
Property
The purpose of this article was to present some ideas for handling large amounts of data, regardless of the control used. It should be noted that the ListView
has a VirtualMode
property. By using this property and supplying additional event code, similar performance increases can be achieved.
For an example of this method, see: ListView in VirtualMode and checkboxes By Alphons van der Heijden.
History
- June 15, 2009: Initial creation of user control and example project.
- July 01, 2009: Update article to reference Alphons van der Heijden's article on using
ListView.VirtualMode
.