

One hundred million points is a stress test that separates chart libraries built for scale from those built for dashboards. On WinUI the split is sharp, because most WinUI charts are managed .NET controls that draw through the XAML layer, while ProEssentials hosts a native Direct3D and Direct2D C++ engine underneath.
We plotted the same 100-million-point signal in five WinUI libraries: ProEssentials, Syncfusion, Telerik, DevExpress and ComponentOne. The code below is the shortest honest path to the chart in each one. The difference is not really the line count, it is what happens to your data on the way to the screen.
ProEssentials reads your float array in place and rebuilds the geometry on the GPU. The four managed suites bind to a collection of objects, one per point, so the same 100 million values balloon into a multi-gigabyte managed heap before anything is drawn.
Reproduce the WinUI numbers yourself: clone, build, run the WinUI 100M-point chart demo on GitHub.Prefer WPF or WinForms? See the WPF 100M-point demo and the WinForms 100M-point demo.
Same data, same machine, five libraries. We measure lines of code, memory overhead, whether it renders at all, and whether the display is lossless or a downsampled approximation.
| Parameter | Value |
|---|---|
| Data points | 100,000,000 (100 million) |
| Data type | float (4 bytes per value) — 400 MB raw data |
| Chart type | 2-D line chart, single series, sequential X-axis |
| Pattern | Sine wave with random noise (realistic signal data) |
| Platform | WinUI 3 (.NET 10), Windows 11, mid-range GPU |
| What we measure | Lines of code, memory overhead, render time, data fidelity |
The pattern below repeats across all five libraries: the code that loads the data matters far more than the code that configures the chart.
The chart reads your existing float array through UseDataAtLocation, so no second copy is ever made. All 100 million values go to the GPU, where the Filter2D3D compute shader runs a conservative min/max pre-filter pass before the final shader constructs the scene. Every point is processed. When the data is denser than the display, the filter keeps 50 min/max pairs per pixel column, or 100 plotted points per pixel, so no spike is discarded and dense regions render as a true solid fill, the same image the full dataset would produce.
// ProEssentials — Plot 100 Million Points (WinUI 3, ~15 lines)
// NuGet: Install-Package ProEssentials.Chart.Net10.WinUI
// Control: PesgoWinUI (named Pesgo1 in XAML). .NET 10, x64 and native ARM64.
// 1. Allocate your data — this is the ONLY copy that will ever exist
float[] yData = new float[100_000_000];
for (int i = 0; i < yData.Length; i++)
yData[i] = (float)Math.Sin(i * 0.0001) + (float)(rand.NextDouble() * 0.1);
// 2. Configure the chart
Pesgo1.PeData.Subsets = 1;
Pesgo1.PeData.Points = 100_000_000;
Pesgo1.PePlot.Method = SGraphPlottingMethod.Line;
Pesgo1.PeConfigure.RenderEngine = RenderEngine.Direct3D;
Pesgo1.PeData.ComputeShader = true; // build chart geometry on the GPU
Pesgo1.PeData.Filter2D3D = true; // lossless GPU min/max pre-filter
Pesgo1.PeData.StagingBufferY = true; // required with ComputeShader
// 3. Zero-copy: point the chart at your existing array — no duplication
Pesgo1.PeData.Y.UseDataAtLocation(yData, yData.Length);
// 4. Rebuild vertices on the GPU and render
Pesgo1.PeFunction.Force3dxVerticeRebuild = true;
Pesgo1.PeFunction.ReinitializeResetImage();
Pesgo1.Invalidate();Presentation is native too. The engine renders into its own DXGI flip-model composition swap chain and hands it to the XAML host through ISwapChainPanelNative::SetSwapChain, so DWM composites the chart straight into your visual tree with no intermediate bitmap and no per-frame CPU copy. It also caps the present queue with SetMaximumFrameLatency(1), which is why a 100-million-point chart still tracks a drag instead of buffering frames ahead of you.
The only memory the chart adds is a small GPU staging buffer. Your 400 MB of data stays your 400 MB, and the same PesgoWinUI control handles 10,000 points or 100 million without a special series type.
The four examples that follow are faithful to each vendor's documented API, and they compile. What they will not do is draw you a chart. Point any of them at 100 million values and the realistic outcomes are an OutOfMemoryException somewhere in the allocation loop, or a wait long enough that you kill the debugger before it finishes. We include the code because it makes the difference concrete, not because we expect anyone to run it at this size. The revealing part of each snippet is not the chart configuration at the bottom; it is the loop at the top that allocates one object per data point.
This is worth keeping in mind when you read performance claims. All four market their charts as high performance, and on the platforms where they actually publish numbers that is a fair claim. The gap is that those are not WinUI numbers.
A note on these numbers. None of the four vendors publishes a large-data benchmark for their WinUI chart specifically. Syncfusion's million-point benchmark is a WPF one. The largest DevExpress figures depend on SwiftPlotSeriesView, a WinForms-only series view. ComponentOne's published Direct2D figure is 50,000 points in roughly 5 ms on a .NET 6 WinForms build. Telerik's guidance for large sets is to aggregate the data down before binding it. We have not benchmarked their WinUI controls ourselves, so we are not going to invent ceilings for them; what we can say is that published evidence for WinUI large-data performance does not yet exist for any of them.
For calibration, here is our own limit. The ProEssentials Direct2D path starts to strain around 3 million points, and that is already with zero-copy loading and no per-point object overhead. The Direct3D compute-shader path is what carries it to 100 million. A managed XAML control that allocates an object per point starts well behind that.
Syncfusion's fast series rasterize the line to a WriteableBitmap, which is a real optimization over the default path. The catch is the data model: the chart binds to a collection of objects, so 100 million points means 100 million allocations long before the bitmap path ever runs.
// Syncfusion — Plot 100 Million Points (WinUI, SfCartesianChart)
// NuGet: Install-Package Syncfusion.Chart.WinUI
// 1. Syncfusion binds to objects — one per point
public class DataPoint { public double X { get; set; } public double Y { get; set; } }
// 2. Build the collection — 100M objects is ~2.4 GB+ with object headers
var data = new List<DataPoint>(100_000_000);
for (int i = 0; i < 100_000_000; i++)
data.Add(new DataPoint { X = i, Y = Math.Sin(i * 0.0001) + rand.NextDouble() * 0.1 });
// This allocation alone risks OutOfMemoryException; the practical ceiling is well below 100M.
// 3. Fast bitmap series — rasterizes the line to a WriteableBitmap
var series = new FastLineBitmapSeries {
ItemsSource = data,
XBindingPath = "X",
YBindingPath = "Y"
};
chart.Series.Add(series);Worth noting where Syncfusion's million-point number comes from: their published benchmark for it is a WPF one, not WinUI. Either way the object-per-point model, not the rasterizer, is what sets the ceiling.
Telerik draws its series through the Composition ContainerVisualsFactory, which keeps ordinary charts smooth. Like Syncfusion, it binds to objects, and its own guidance for large data is to downsample before you hand the data to the chart.
// Telerik — Plot 100 Million Points (WinUI, RadCartesianChart)
// NuGet: Install-Package Telerik.WinUI.Controls (license key required)
// 1. Telerik binds to objects — one per point
public class DataPoint { public double X { get; set; } public double Y { get; set; } }
// 2. Build the collection (~2.4 GB+ at 100M objects)
var data = new ObservableCollection<DataPoint>();
for (int i = 0; i < 100_000_000; i++)
data.Add(new DataPoint { X = i, Y = Math.Sin(i * 0.0001) + rand.NextDouble() * 0.1 });
// 3. Line series — drawn through the Composition ContainerVisualsFactory
var series = new LineSeries {
ItemsSource = data,
CategoryBinding = new PropertyNameDataPointBinding { PropertyName = "X" },
ValueBinding = new PropertyNameDataPointBinding { PropertyName = "Y" }
};
// For large data, Telerik expects you to downsample before binding.
radChart.Series.Add(series);Downsampling first means the chart never sees all 100 million points, which is a reasonable strategy, just not a lossless one.
The DevExpress WinUI ChartControl binds a DataSource with argument and value members. For large sets, DevExpress recommends turning on data sampling so the control renders a representative subset rather than every point.
// DevExpress — Plot 100 Million Points (WinUI, ChartControl)
// NuGet: DevExpress WinUI packages (private feed, credentials required)
// 1. DevExpress binds to objects — one per point
public class DataPoint { public double Argument { get; set; } public double Value { get; set; } }
// 2. Build the collection (~2.4 GB+ at 100M objects)
var data = new List<DataPoint>(100_000_000);
for (int i = 0; i < 100_000_000; i++)
data.Add(new DataPoint { Argument = i, Value = Math.Sin(i * 0.0001) + rand.NextDouble() * 0.1 });
// 3. Line series on the ChartControl — bind DataSource + data members
var series = new LineSeries();
series.DataSource = data;
series.ArgumentDataMember = "Argument";
series.ValueDataMember = "Value";
chartControl.Series.Add(series);
// DevExpress recommends data sampling to keep large sets responsive.Sampling keeps the UI responsive, but the same object-per-point allocation applies before any of that happens.
ComponentOne is the one competitor with a Direct2D render mode, and it is a real optimization over its default path. It is still a managed control binding to an object collection, so the memory story matches the others. On throughput, the concrete figure ComponentOne publishes for Direct2D is 50,000 points in roughly 5 ms, measured on a .NET 6 WinForms build rather than WinUI.
// ComponentOne (MESCIUS) — Plot 100 Million Points (WinUI, FlexChart)
// NuGet: Install-Package C1.WinUI.Chart
// 1. FlexChart binds to objects — one per point
public class DataPoint { public double X { get; set; } public double Y { get; set; } }
// 2. Build the collection (~2.4 GB+ at 100M objects)
var data = new List<DataPoint>(100_000_000);
for (int i = 0; i < 100_000_000; i++)
data.Add(new DataPoint { X = i, Y = Math.Sin(i * 0.0001) + rand.NextDouble() * 0.1 });
// 3. Bind the chart, then switch on the Direct2D render mode for large data
flexChart.ItemsSource = data;
flexChart.BindingX = "X";
flexChart.Series.Add(new Series { Binding = "Y" });
flexChart.RenderMode = RenderMode.Direct2D; // required to draw millions of pointsDirect2D mode is the closest a managed WinUI chart gets to the native approach, and it is worth knowing about when you compare honestly.
The memory rows are simple arithmetic, not benchmarks: 100 million floats are 400 MB, while 100 million bound objects carry gigabytes of headers and references before a single pixel is drawn.
| Factor | ProEssentials | Syncfusion | Telerik | DevExpress | ComponentOne |
|---|---|---|---|---|---|
| Renders 100M in real time? | ✅ Yes — natively | ❌ OOM well before 100M | ⚠️ Aggregate first | ⚠️ Sample first | ⚠️ Direct2D mode (50k published) |
| Rendering | Native Direct3D compute | WriteableBitmap | Composition visuals | Managed XAML | Direct2D (optional) |
| Data model | Zero-copy float[] pointer | Object-per-point | Object-per-point | Object-per-point | Object-per-point |
| Memory: your data | 400 MB | 400 MB | 400 MB | 400 MB | 400 MB |
| Memory: library overhead | ~0 MB | ~2,400 MB+ | ~2,400 MB+ | ~2,400 MB+ | ~2,400 MB+ |
| Total memory | ~400 MB | OOM risk | ~2,800 MB (or downsampled) | ~2,800 MB (or sampled) | ~2,800 MB |
| Special series type? | No — same control | FastLineBitmapSeries | Sampling settings | Sampling settings | Direct2D render mode |
| Full-fidelity display | Lossless GPU min/max | Bitmap raster | Downsampled subset | Sampled subset | Direct2D raster |
| Native ARM64 | Yes — native binary | Managed | Managed | Managed | Managed |
The number that decides everything at this scale is not frames per second, it is how many times your data gets copied on the way to the screen.
ProEssentials copies it zero times. It reads the float array you already allocated and rebuilds the picture on the GPU. A managed chart that binds to a collection copies each value into an object with headers and references, which is where the gigabytes come from.
At a few thousand points nobody notices. At a hundred million, that one design choice is the difference between a 400 MB app and one that runs out of memory.
| Data Model | Overhead (100M pts) | Used By |
|---|---|---|
| Zero-copy pointer | ~0 MB | ProEssentials |
| Array copy (float) | ~400 MB | — |
| Object-per-point | ~2,400 MB+ | Syncfusion, Telerik, DevExpress, ComponentOne |
Fast rendering cannot rescue a data model that allocates an object per point. The managed suites reach for downsampling and bitmap fast-paths precisely because the object model will not hold 100 million points. ProEssentials never creates the problem.
All five libraries draw a nice line chart. Only one draws 100 million points losslessly and in real time, without making you downsample your data, switch series types, or accept a multi-gigabyte heap. That is the payoff of a native engine that reads your data where it already lives.
If your WinUI app plots thousands of points, pick whatever suite you already own. If it plots millions to hundreds of millions, the data model is the whole game, and ProEssentials is the one built for it.
Competitor rendering approaches and binding APIs are drawn from each vendor's own documentation:
Syncfusion (WinUI SfCartesianChart)
Telerik (UI for WinUI RadChart)
DevExpress (WinUI ChartControl)
ComponentOne / MESCIUS (FlexChart for WinUI)
Tell us how many points you need to plot and how they update. The developers who built the engine will tell you honestly whether ProEssentials fits.
Contact usYour success is our #1 goal by providing the easiest and most professional benefit to your organization and end-users.
ProEssentials was born from professional Electrical Engineers needing their own charting components. Join our large list of top engineering companies using ProEssentials.
Thank you for being a ProEssentials customer, and thank you for researching the ProEssentials charting engine.