Pivot
The cross-tabulation engine on its own: a flat sequence in, two trees of headings and the values where they cross out, with no markup. Give PivotBuilder fields for the rows, fields for the columns and one or more measures, and it works out every heading and every cell.
This is a static class, not a Blazor component
Call
PivotBuilder.Build from C# when the table is going somewhere that is not a Blazor page — a report, a CSV, a spreadsheet.
For a page, use BbPivotDataGrid, which renders the same result as a table.
Build It, Then Render It Yourself
Build returns a PivotTable: two trees of headings, the measures, and GetValue to read where a row and a column cross. The table below is drawn in this page from RowLeaves, ColumnLeaves and GetValue — nothing else. Values are worked out the first time they are asked for and then kept, so reading the same cell twice costs nothing the second time.A Total Is Worked Out From Every Item Under It
Items are bucketed in one pass and each bucket keeps its items, so a total re-runs the aggregate over everything beneath it rather than adding up the cells it covers. For a
Sum the two answers agree and nobody notices. For an Average they do not, and an average of averages is wrong in a way that is invisible until someone checks. The two columns below show the difference on the same data.Label Formats, It Does Not Group
The grouping and the sorting still use the real value. Group on the month number and label it with the month name, and the headings come out Jan, Feb, Mar. Group on the name and they come out Apr, Aug, Dec.
Drilling Down
GetItems returns the source items behind a cell, which is what a drill-down shows. A total's items are every item under it, not the cells it sums — which is the same mechanism that makes a custom aggregate come out right on a total.LeafIndex and DataIndex Are Not the Same Sequence
Totals are drawn between the data, so the drawn order and the data order diverge. Use
LeafIndex to place a cell and DataIndex to address a bucket. A total reports DataIndex of -1.