Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Data Virtualization using DataGrid

5.00/5 (7 votes)
30 Oct 2018CPOL2 min read 24K   994  
Data Virtualization example with a pagesize and async data request

Introduction

Using the DataGrid for millions of rows with a slow datasource will cause the user interface to freeze and give the end user a bad experience. UI virtualization comes automatically with the VirtualizationStackPanel inside the DataGrid, but Data Virtualization is not provided out of the box. Data Virtualization is the feature of providing only the data needed to present for the end user.

Typically, around 20-100 rows will be shown at a time. When the user starts scrolling, data virtualization is used to provide the requested rows. In this example, the pagesize is set to 20. What it means is that when the DataGrid is requesting a row, the next 20 rows will actually be loaded and prepared for presentation.

The idea is to use a CollectionView to encapsulate a DataTable. For the purpose, I have created a CollectionView called DataGridCollectionView. The DataGridCollectionView will be used as datasource for the ItemsSource property of the DataGrid. When the DataGrid is loaded, it will call out for row numbers 0, 1, 2, 3, etc. until the available space is filled. To be more effective than loading just one row at the time, the example here is using a pagesize so you batch load your rows.

Using the Code

The DataGridCollectionView comes with two events:

  • ItemsCount
  • ItemsRequest

The idea is that the ItemsCount is raised to tell the DataGrid how many rows can be expected.

The ItemsRequest is the actual request for items. The request is done in a background thread and has a startindex (the row number) and the number of items to provide. An Item is a DataRow in this example.

You hook it up like this:

C#
DataGridCollectionView dataGridCollectionView = new DataGridCollectionView(dataTable);
dataGridCollectionView.ItemsCount += OnItemsCount;
dataGridCollectionView.ItemsRequest += OnItemsRequest;

In the event handlers for this example, the count and DataRows are provided like this:

C#
private void OnItemsCount(DataGridCollectionView arg1, CountEventArgs arg2)
{
   arg2.Count = Count;
}

private void OnItemsRequest(DataGridCollectionView arg1, ItemsEventArgs arg2)
{
    int startIndex = arg2.StartIndex;
    int count = arg2.RequestedItemsCount;

    List<object> items = new List<object>();
    for (int i = startIndex; i < startIndex + count; i++)
    {
         DataRow row = dataTable.NewRow();

          row[0] = i.ToString();
          row[1] = rnd.Next(1000).ToString();
          row[2] = rnd.Next(1000).ToString();

          items.Add(row);
          //Simulating heavy loading time
          Thread.Sleep(10);                
     }

     arg2.SetItems(items);
}

As can be seen, you give back the rows in the SetItems method. The DataTable as you probably have guessed has 3 columns since the DataRow consists of 3 cells. You should easily be able to adapt this to your own needs.

The example is using the standard Model-View-ViewModel pattern.

The main XAML code defining the DataGrid.

XML
<DataGrid ItemsSource="{Binding TableSource, Mode=OneWay}" AutoGenerateColumns="False">
     <DataGrid.Columns>
          <DataGridTextColumn Binding="{Binding Path=[0]}" Header="Row number" />
          <DataGridTextColumn Binding="{Binding Path=[1]}" Header="column 2"/>
          <DataGridTextColumn Binding="{Binding Path=[2]}" Header="column 3"/>
     </DataGrid.Columns>
</DataGrid>

The ViewModel contains a property called TableSource that is the DataGridCollectionView.

A demo project is attached that should clear up most questions.

History

  • 29th October, 2018: Initial version

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)