How to Load a Billion Rows in a WPF Datagrid
Tags: webdev, dotnet, tutorial, devops
Published: 2022-08-19 21:47:14

---
canonical_url: https://www.grapecity.com/blogs/how-to-load-a-billion-rows-in-a-wpf-datagrid
description: Watch in this tutorial as we load one BILLION rows of data in a WPF datagrid application. See more from ComponentOne today.
---

Support for large data sets is one of the most requested features for UI controls and one of our key investment areas. When dealing with large datasets, there are two critical things to consider: the memory footprint and the performance. The best way to solve this is with **data virtualization** - which allows you to have an overall view of the entire data set without needing it all physically in one location.

Common data virtualization solutions often include client-side pagination or cursor lists. These techniques, however, bring usability implications to users, and, in most cases, we wish to have the ease of scrolling the whole dataset like normal.

With our .NET 6 FlexGrid for WPF, we had effectively implemented solutions to quickly work with multiple millions of rows. Still, we discovered significant issues with performance and memory when it reached one billion rows.

Check out in action [here](https://www.youtube.com/watch?v=642Q_LjfjJU)!

So, we decided to push the performance limitations further by implementing new techniques and overcoming every tiny bottleneck to tackle this and allow any number of rows to be displayed in FlexGrid.

The first thing to consider when wanting to display that number of items is that the dataset cannot be all in memory. Creating a List<T> of 1 billion nulls generally takes around 15 seconds and consumes 8GB of memory. Therefore, it requires a data virtualization solution.

For this purpose, we provide the abstract **C1VirtualDataCollection** class, which is part of the [ComponentOne DataCollection](https://www.nuget.org/packages/C1.DataCollection/) library. You can inherit this collection to provide your virtualized content. An example implementation looks like this:

```
        public class VirtualModeDataCollection : C1VirtualDataCollection<Customer>
        {
            public int TotalCount { get; set; } = 1_000_000_000;

            protected override async Task<Tuple<int, IReadOnlyList<Customer>>> GetPageAsync(int pageIndex, int startingIndex, int count, IReadOnlyList<SortDescription> sortDescriptions = null, FilterExpression filterExpression = null, CancellationToken cancellationToken = default(CancellationToken))
            {
                return new Tuple<int, IReadOnlyList<Customer>>(TotalCount, Enumerable.Range(startingIndex, count).Select(i => new Customer(i)).ToList());
            }
        }
```

To test the performance and memory footprint, we will create the collection and load the first page, which is similar to what happens when visualizing the collection in FlexGrid. And we will repeat the same for the previous collection and the one containing the improvements.

<table border="0" width="759" style="font-weight: 400;">

<tbody>

<tr>

<td>

Performance (ms)

</td>

<td>

C1DataCollection 1.0.20221.66

</td>

<td>

C1DataCollection 1.0.20222.87

</td>

</tr>

<tr>

<td>

1 hundred

</td>

<td>

309

</td>

<td>

306

</td>

</tr>

<tr>

<td>

10 hundred

</td>

<td>

302

</td>

<td>

304

</td>

</tr>

<tr>

<td>

100 hundred

</td>

<td>

310

</td>

<td>

313

</td>

</tr>

<tr>

<td>

1 million

</td>

<td>

320

</td>

<td>

312

</td>

</tr>

<tr>

<td>

10 million

</td>

<td>

481

</td>

<td>

301

</td>

</tr>

<tr>

<td>

100 million

</td>

<td>

1,910

</td>

<td>

306

</td>

</tr>

<tr>

<td>

1 billion

</td>

<td>

15,777

</td>

<td>

313

</td>

</tr>

</tbody>

</table>

![Performance of C1VirtualDataCollection](https://files.grapecity.com/gc-website-media/vhyjfnlf/01-billion.png?width=500&height=290.53177691309986)

<table border="0" width="759" style="font-weight: 400;">

<tbody>

<tr>

<td>

Memory (bytes)

</td>

<td>

C1DataCollection 1.0.20221.66

</td>

<td>

C1DataCollection 1.0.20222.87

</td>

</tr>

<tr>

<td>

1 hundred

</td>

<td>

19,776

</td>

<td>

19,608

</td>

</tr>

<tr>

<td>

10 hundred

</td>

<td>

143,240

</td>

<td>

29,920

</td>

</tr>

<tr>

<td>

100 hundred

</td>

<td>

1,061,096

</td>

<td>

29,936

</td>

</tr>

<tr>

<td>

1 million

</td>

<td>

8,401,408

</td>

<td>

27,672

</td>

</tr>

<tr>

<td>

10 million

</td>

<td>

134,230,344

</td>

<td>

36,264

</td>

</tr>

<tr>

<td>

100 million

</td>

<td>

1,073,754,680

</td>

<td>

35,960

</td>

</tr>

<tr>

<td>

1 billion

</td>

<td>

8,589,947,776

</td>

<td>

36,400

</td>

</tr>

</tbody>

</table>

![Memory Footprint of C1VirtualDataCollection](https://files.grapecity.com/gc-website-media/ncicygsw/02-billion.png?width=500&height=289.94614003590664)

As you can see, the performance for loading the first page in the new version is unaltered, and the memory footprint is insignificant, even for the billion-items case. The latest version of C1VirtualDataCollection now uses a dynamic list internally that takes almost nothing to be created and uses minimal memory.

### Skeleton Loading in FlexGrid

While most of the performance enhancements are within the DataCollection, there are some improvements in FlexGrid.

We took this opportunity to introduce another new feature in FlexGrid that helps with a perceived performance called **Skeleton Loading**. This feature shows an animated “skeleton” placeholder inside every cell, indicating the data is being loaded underneath. You can enable this feature in FlexGrid through behavior as seen below:

```
    <c1:FlexGrid>
        <i:Interaction.Behaviors>
            <c1:SkeletonLoadingBehavior />
        </i:Interaction.Behaviors>
    </c1:FlexGrid>
```

### ![Billion Rows](https://files.grapecity.com/gc-website-media/1rdbx0eh/03-billion.gif?width=500&height=290)

### FlexGrid Overcomes WPF Layout Limits

Another improvement to FlexGrid was concerning rendering cells correctly for very large offsets.

As we worked out the scrolling performance in FlexGrid, we found some limits in the platform in terms of positioning the elements in the layout with huge numbers. We discovered that the content began to look displaced when rendering more than 2 million rows (30 pixels per row).

We reproduced this limitation with a ScrollViewer and simple TextBlocks. When the positioning goes past 60 million pixels or 2 million rows, the TextBlocks are positioned incorrectly.

![ScrollViewer](https://files.grapecity.com/gc-website-media/frxj1okw/04-billion.png?width=500&height=282)

So, we discovered that ScrollViewer is only good at positioning items up to a certain length, up to about 60 million pixels. After about 9 million rows (270 million pixels), the text stops rendering completely. If you are curious to try this yourself, you can download the sample [here](https://files.grapecity.com/gc-website-media/rotha54d/wpflayoutlimits.zip).

This limitation was overcome in FlexGrid 2022 v2 as we can go well beyond even 9 million rows to display up to one billion rows successfully. In theory, our WPF Datagrid can display more rows, but we stopped at one billion for this demonstration.

You can download the ComponentOne 2022 v2 update of WPF Edition to see the new FlexGrid Virtual Mode sample and see for yourself how it performs with one billion rows.