|
| 1 | +@using System |
| 2 | +@using System.Collections.Generic |
| 3 | +@using System.Linq |
| 4 | +@using Microsoft.EntityFrameworkCore |
| 5 | +@using Radzen |
| 6 | +@using Radzen.Blazor |
| 7 | +@inherits RadzenBlazorDemos.Shared.DbContextPage |
| 8 | + |
| 9 | +<RadzenCard Variant="Variant.Outlined" class="rz-my-4"> |
| 10 | + <RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" Style="margin:1rem"> |
| 11 | + <RadzenSwitch @bind-Value="@showColumnTotals" Name="ShowColumnTotals" /> |
| 12 | + <RadzenLabel Text="Show column totals" Component="ShowColumnTotals" /> |
| 13 | + <RadzenSwitch @bind-Value="@showRowTotals" Name="ShowRowTotals" /> |
| 14 | + <RadzenLabel Text="Show row totals" Component="ShowRowTotals" /> |
| 15 | + <RadzenSwitch @bind-Value="@allowDrillDown" Name="AllowDrillDown" /> |
| 16 | + <RadzenLabel Text="Allow drill-down" Component="AllowDrillDown" /> |
| 17 | + <RadzenSwitch @bind-Value="@allowPaging" Name="AllowPaging" /> |
| 18 | + <RadzenLabel Text="Allow paging" Component="AllowPaging" /> |
| 19 | + <RadzenDropDown @bind-Value="@pagerPosition" |
| 20 | + Visible="@allowPaging" |
| 21 | + TextProperty="Text" |
| 22 | + ValueProperty="Value" |
| 23 | + Data="@(Enum.GetValues(typeof(PagerPosition)).Cast<PagerPosition>().Select(t => new { Text = $"{t}", Value = t }))" /> |
| 24 | + </RadzenStack> |
| 25 | + <RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" Style="margin:1rem"> |
| 26 | + <RadzenSwitch @bind-Value="@allowFieldsPicking" Name="AllowFieldsPicking" /> |
| 27 | + <RadzenLabel Text="Allow fields picking" Component="AllowFieldsPicking" /> |
| 28 | + <RadzenSwitch @bind-Value="@allowSorting" Name="AllowSorting" Visible="@allowFieldsPicking" /> |
| 29 | + <RadzenLabel Text="Allow sorting" Component="AllowSorting" Visible="@allowFieldsPicking" /> |
| 30 | + <RadzenSwitch @bind-Value="@allowFiltering" Name="AllowFiltering" Visible="@allowFieldsPicking" /> |
| 31 | + <RadzenLabel Text="Allow filtering" Component="AllowFiltering" Visible="@allowFieldsPicking" /> |
| 32 | + </RadzenStack> |
| 33 | +</RadzenCard> |
| 34 | + |
| 35 | +<RadzenPivotDataGrid Data="@data" |
| 36 | + TItem="IDictionary<string, object>" |
| 37 | + AllowSorting="@allowSorting" |
| 38 | + AllowFiltering="@allowFiltering" |
| 39 | + AllowDrillDown="@allowDrillDown" |
| 40 | + AllowFieldsPicking="@allowFieldsPicking" |
| 41 | + ShowColumnsTotals="@showColumnTotals" |
| 42 | + ShowRowsTotals="@showRowTotals" |
| 43 | + AllowPaging="@allowPaging" |
| 44 | + PagerPosition="@pagerPosition" |
| 45 | + PageSize="20" |
| 46 | + AllowAlternatingRows="true" |
| 47 | + GridLines="Radzen.DataGridGridLines.Default" |
| 48 | + Style="height: 700px;"> |
| 49 | + <Columns> |
| 50 | + @foreach (var field in columnFields) |
| 51 | + { |
| 52 | + <RadzenPivotColumn @key="@field.Property" |
| 53 | + Title="@field.Title" |
| 54 | + Width="@field.Width" |
| 55 | + Type="@field.Type" |
| 56 | + Property="@PropertyAccess.GetDynamicPropertyExpression(field.Property, field.Type)" /> |
| 57 | + } |
| 58 | + </Columns> |
| 59 | + <Rows> |
| 60 | + @foreach (var field in rowFields) |
| 61 | + { |
| 62 | + <RadzenPivotRow @key="@field.Property" |
| 63 | + Title="@field.Title" |
| 64 | + Type="@field.Type" |
| 65 | + Property="@PropertyAccess.GetDynamicPropertyExpression(field.Property, field.Type)" /> |
| 66 | + } |
| 67 | + </Rows> |
| 68 | + <Aggregates> |
| 69 | + @foreach (var aggregate in aggregateFields) |
| 70 | + { |
| 71 | + <RadzenPivotAggregate @key="@aggregate.Property" |
| 72 | + Title="@aggregate.Title" |
| 73 | + Type="@aggregate.Type" |
| 74 | + Property="@PropertyAccess.GetDynamicPropertyExpression(aggregate.Property, aggregate.Type)" |
| 75 | + Aggregate="@aggregate.Aggregate" |
| 76 | + FormatString="@aggregate.FormatString" |
| 77 | + TextAlign="@aggregate.TextAlign" /> |
| 78 | + } |
| 79 | + </Aggregates> |
| 80 | +</RadzenPivotDataGrid> |
| 81 | + |
| 82 | +@code { |
| 83 | + private readonly IReadOnlyList<PivotFieldDescriptor> columnFields = new[] |
| 84 | + { |
| 85 | + new PivotFieldDescriptor("OrderYear", "Order Year", typeof(int?), "140px"), |
| 86 | + new PivotFieldDescriptor("ShipCountry", "Ship Country", typeof(string), "180px") |
| 87 | + }; |
| 88 | + |
| 89 | + private readonly IReadOnlyList<PivotFieldDescriptor> rowFields = new[] |
| 90 | + { |
| 91 | + new PivotFieldDescriptor("Category", "Category", typeof(string)), |
| 92 | + new PivotFieldDescriptor("Product", "Product", typeof(string)) |
| 93 | + }; |
| 94 | + |
| 95 | + private readonly IReadOnlyList<PivotAggregateDescriptor> aggregateFields = new[] |
| 96 | + { |
| 97 | + new PivotAggregateDescriptor("TotalSales", "Total Sales", typeof(double), AggregateFunction.Sum, "{0:C}", TextAlign.Right), |
| 98 | + new PivotAggregateDescriptor("Quantity", "Quantity", typeof(int), AggregateFunction.Sum, "{0:N0}", TextAlign.Right), |
| 99 | + new PivotAggregateDescriptor("Discount", "Average Discount", typeof(double), AggregateFunction.Average, "{0:P1}", TextAlign.Right), |
| 100 | + new PivotAggregateDescriptor("UnitPrice", "Average Unit Price", typeof(double), AggregateFunction.Average, "{0:C}", TextAlign.Right) |
| 101 | + }; |
| 102 | + |
| 103 | + private List<IDictionary<string, object>> data = new List<IDictionary<string, object>>(); |
| 104 | + private bool allowDrillDown = true; |
| 105 | + private bool allowFieldsPicking = true; |
| 106 | + private bool allowSorting = true; |
| 107 | + private bool allowFiltering = true; |
| 108 | + private bool allowPaging = true; |
| 109 | + private bool showColumnTotals = true; |
| 110 | + private bool showRowTotals = true; |
| 111 | + private PagerPosition pagerPosition = PagerPosition.Bottom; |
| 112 | + |
| 113 | + protected override async Task OnInitializedAsync() |
| 114 | + { |
| 115 | + await base.OnInitializedAsync(); |
| 116 | + |
| 117 | + var sales = await (from od in dbContext.OrderDetails |
| 118 | + join o in dbContext.Orders on od.OrderID equals o.OrderID |
| 119 | + join p in dbContext.Products on od.ProductID equals p.ProductID |
| 120 | + join c in dbContext.Categories on p.CategoryID equals c.CategoryID |
| 121 | + select new |
| 122 | + { |
| 123 | + CategoryName = c.CategoryName, |
| 124 | + ProductName = p.ProductName, |
| 125 | + OrderYear = o.OrderDate.HasValue ? o.OrderDate.Value.Year : 0, |
| 126 | + ShipCountry = o.ShipCountry, |
| 127 | + UnitPrice = od.UnitPrice ?? 0, |
| 128 | + Quantity = od.Quantity ?? 0, |
| 129 | + Discount = od.Discount ?? 0, |
| 130 | + TotalAmount = (od.UnitPrice ?? 0) * (od.Quantity ?? 0) * (1 - (od.Discount ?? 0)) |
| 131 | + }).ToListAsync(); |
| 132 | + |
| 133 | + data = sales.Select(result => |
| 134 | + { |
| 135 | + var row = new Dictionary<string, object> |
| 136 | + { |
| 137 | + ["OrderYear"] = result.OrderYear, |
| 138 | + ["ShipCountry"] = string.IsNullOrEmpty(result.ShipCountry) ? "Unknown" : result.ShipCountry, |
| 139 | + ["Category"] = result.CategoryName ?? "(no category)", |
| 140 | + ["Product"] = result.ProductName ?? "(no product)", |
| 141 | + ["Quantity"] = result.Quantity, |
| 142 | + ["UnitPrice"] = result.UnitPrice, |
| 143 | + ["Discount"] = result.Discount, |
| 144 | + ["TotalSales"] = result.TotalAmount |
| 145 | + }; |
| 146 | + |
| 147 | + return (IDictionary<string, object>)row; |
| 148 | + }).ToList(); |
| 149 | + } |
| 150 | + |
| 151 | + |
| 152 | + private sealed record PivotFieldDescriptor(string Property, string Title, Type Type, string? Width = null); |
| 153 | + |
| 154 | + private sealed record PivotAggregateDescriptor(string Property, |
| 155 | + string Title, |
| 156 | + Type Type, |
| 157 | + AggregateFunction Aggregate, |
| 158 | + string? FormatString, |
| 159 | + TextAlign TextAlign); |
| 160 | +} |
| 161 | + |
0 commit comments