mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e03c4377f | ||
|
|
7497ea1262 | ||
|
|
d68bb34f6f | ||
|
|
732a6f4942 | ||
|
|
70fb896ae1 | ||
|
|
034eae6722 | ||
|
|
3472949bf0 | ||
|
|
c333b8ca30 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
dotnet-version: 10.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build Radzen.Blazor/Radzen.Blazor.csproj
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0
|
||||
|
||||
COPY Radzen.Blazor /app/Radzen.Blazor
|
||||
COPY Radzen.DocFX /app/Radzen.DocFX
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Radzen.Blazor.Tests
|
||||
public Guid Id { get; set; }
|
||||
public TimeOnly StartTime { get; set; }
|
||||
public DateOnly BirthDate { get; set; }
|
||||
public int[] Scores { get; set; }
|
||||
public List<int> Scores { get; set; }
|
||||
public List<string> Tags { get; set; }
|
||||
public List<TestEntity> Children { get; set; }
|
||||
public Address Address { get; set; }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||
<PackageReference Include="bunit.web" Version="1.36.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
|
||||
@@ -87,10 +87,9 @@ public class AIChatService(IServiceProvider serviceProvider, IOptions<AIChatServ
|
||||
|
||||
var assistantResponse = new StringBuilder();
|
||||
|
||||
while (!reader.EndOfStream && !cancellationToken.IsCancellationRequested)
|
||||
string line;
|
||||
while ((line = await reader.ReadLineAsync()) is not null && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var line = await reader.ReadLineAsync();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(line) || !line.StartsWith("data:"))
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -385,7 +385,8 @@ namespace Radzen
|
||||
}
|
||||
else
|
||||
{
|
||||
member = Expression.PropertyOrField(expression, currentPart);
|
||||
var p = expression.Type.GetProperty(currentPart, BindingFlags.Public | BindingFlags.Instance);
|
||||
member = p != null ? Expression.Property(expression, p) : Expression.PropertyOrField(expression, currentPart);
|
||||
}
|
||||
|
||||
if (expression.Type.IsValueType && Nullable.GetUnderlyingType(expression.Type) == null)
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<NoWarn>BL9993;BL0007;BL0005</NoWarn>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<RazorLangVersion>7.0</RazorLangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<OutputType>Library</OutputType>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Radzen.Blazor</PackageId>
|
||||
<Product>Radzen.Blazor</Product>
|
||||
<Version>8.2.2</Version>
|
||||
<Version>8.3.0</Version>
|
||||
<Copyright>Radzen Ltd.</Copyright>
|
||||
<Authors>Radzen Ltd.</Authors>
|
||||
<Description>Radzen Blazor is the most sophisticated free UI component library for Blazor, featuring 100+ native components including DataGrid, Scheduler, Charts, and advanced theming with full support for Material Design and Fluent UI.</Description>
|
||||
@@ -34,6 +34,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.*-*" />
|
||||
<PackageReference Include="Radzen.Terser.MSBuild" Version="0.0.4" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -55,10 +57,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net9.0'" />
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net10.0'" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<PropertyGroup>
|
||||
<_SassFileList>@(Sass->'"%(FullPath)"', ' ')</_SassFileList>
|
||||
<DartSassBuilderArgs>files $(_SassFileList) --outputstyle $(DartSassOutputStyle) --level $(DartSassOutputLevel)</DartSassBuilderArgs>
|
||||
@@ -67,14 +69,14 @@
|
||||
<Message Text="Converted SassFile list to argument" Importance="$(DartSassMessageLevel)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<ItemGroup>
|
||||
<CssFile Include="$(MSBuildProjectDirectory)/themes/*.css" />
|
||||
</ItemGroup>
|
||||
<Move SourceFiles="@(CssFile)" DestinationFolder="$(MSBuildProjectDirectory)/wwwroot/css/" />
|
||||
</Target>
|
||||
|
||||
<Target Name="MinifyTest" BeforeTargets="Build" Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<Target Name="MinifyTest" BeforeTargets="Build" Condition="'$(TargetFramework)' == 'net10.0'">
|
||||
<TerserMinify InputFile="wwwroot\Radzen.Blazor.js" OutputFile="wwwroot\Radzen.Blazor.min.js" />
|
||||
</Target>
|
||||
|
||||
|
||||
@@ -2183,7 +2183,15 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Data != null && !LoadData.HasDelegate)
|
||||
{
|
||||
#if NET10_0_OR_GREATER
|
||||
var count = View.Count();
|
||||
if (count != Count)
|
||||
{
|
||||
Count = count;
|
||||
}
|
||||
#else
|
||||
Count = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (AllowVirtualization)
|
||||
|
||||
@@ -950,7 +950,14 @@ namespace Radzen.Blazor
|
||||
|
||||
for (int i = 0; i < colPath.Count; i++)
|
||||
{
|
||||
items = items.Where($"i => i.{pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
if (pivotColumns[i].Property.Contains("it["))
|
||||
{
|
||||
items = items.Where($"it => {pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
}
|
||||
else
|
||||
{
|
||||
items = items.Where($"i => i.{pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
}
|
||||
}
|
||||
|
||||
var total = GetAggregateValue(items, aggregate);
|
||||
@@ -1023,7 +1030,14 @@ namespace Radzen.Blazor
|
||||
continue; // Skip padding cells added to align depths
|
||||
}
|
||||
|
||||
items = items.Where($@"i => i.{pivotRows[i].Property} == {ExpressionSerializer.FormatValue(cell.Value)}");
|
||||
if (pivotRows[i].Property.Contains("it["))
|
||||
{
|
||||
items = items.Where($@"it => {pivotRows[i].Property} == {ExpressionSerializer.FormatValue(cell.Value)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
items = items.Where($@"i => i.{pivotRows[i].Property} == {ExpressionSerializer.FormatValue(cell.Value)}");
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
@@ -1131,7 +1145,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
else
|
||||
{
|
||||
values = items.Select(aggregate.Property).Cast(propertyType);
|
||||
values = propertyType != null ? items.Select(aggregate.Property).Cast(propertyType) : items.Select(aggregate.Property);
|
||||
}
|
||||
|
||||
switch (aggregate.Aggregate)
|
||||
@@ -1249,7 +1263,14 @@ namespace Radzen.Blazor
|
||||
var items = node.Items;
|
||||
for (int i = 0; i < colPath.Count; i++)
|
||||
{
|
||||
items = items.Where($"i => i.{pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
if (pivotColumns[i].Property.Contains("it["))
|
||||
{
|
||||
items = items.Where($"it => {pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
}
|
||||
else
|
||||
{
|
||||
items = items.Where($"i => i.{pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
}
|
||||
}
|
||||
row.ValueCells.Add(items.Count() > 0 ? GetAggregateValue(items, aggregate) : null);
|
||||
}
|
||||
@@ -1289,12 +1310,26 @@ namespace Radzen.Blazor
|
||||
// Filter by row path
|
||||
for (int i = 0; i < newPrefix.Count && i < pivotRows.Count; i++)
|
||||
{
|
||||
items = items.Where($@"i => i.{pivotRows[i].Property} == {ExpressionSerializer.FormatValue(newPrefix[i].Value)}");
|
||||
if (pivotRows[i].Property.Contains("it["))
|
||||
{
|
||||
items = items.Where($@"it => {pivotRows[i].Property} == {ExpressionSerializer.FormatValue(newPrefix[i].Value)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
items = items.Where($@"i => i.{pivotRows[i].Property} == {ExpressionSerializer.FormatValue(newPrefix[i].Value)}");
|
||||
}
|
||||
}
|
||||
// Filter by column path
|
||||
for (int i = 0; i < colPath.Count; i++)
|
||||
{
|
||||
items = items.Where($"i => i.{pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
if (pivotColumns[i].Property.Contains("it["))
|
||||
{
|
||||
items = items.Where($"it => {pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
}
|
||||
else
|
||||
{
|
||||
items = items.Where($"i => i.{pivotColumns[i].Property} == {ExpressionSerializer.FormatValue(colPath[i])}");
|
||||
}
|
||||
}
|
||||
collapsedRow.ValueCells.Add(items.Count() > 0 ? GetAggregateValue(items, aggregate) : null);
|
||||
}
|
||||
@@ -1752,7 +1787,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
field.SetSecondFilterValueInternal(value);
|
||||
}
|
||||
StateHasChanged();
|
||||
InvokeAsync(OnFilterChanged);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1960,12 +1995,12 @@ namespace Radzen.Blazor
|
||||
|
||||
var innerFilterExpressions = new List<CompositeFilterDescriptor>();
|
||||
|
||||
var filterExpression = BuildFilterExpression(property, filterValue, filterOperator);
|
||||
var filterExpression = BuildFilterExpression(property, filterValue, filterOperator, column.Type);
|
||||
innerFilterExpressions.Add(filterExpression);
|
||||
|
||||
if (secondFilterValue != null)
|
||||
{
|
||||
var secondFilterExpression = BuildFilterExpression(property, secondFilterValue, secondFilterOperator);
|
||||
var secondFilterExpression = BuildFilterExpression(property, secondFilterValue, secondFilterOperator, column.Type);
|
||||
innerFilterExpressions.Add(secondFilterExpression);
|
||||
}
|
||||
|
||||
@@ -1992,12 +2027,12 @@ namespace Radzen.Blazor
|
||||
|
||||
var innerFilterExpressions = new List<CompositeFilterDescriptor>();
|
||||
|
||||
var filterExpression = BuildFilterExpression(property, filterValue, filterOperator);
|
||||
var filterExpression = BuildFilterExpression(property, filterValue, filterOperator, row.Type);
|
||||
innerFilterExpressions.Add(filterExpression);
|
||||
|
||||
if (secondFilterValue != null)
|
||||
{
|
||||
var secondFilterExpression = BuildFilterExpression(property, secondFilterValue, secondFilterOperator);
|
||||
var secondFilterExpression = BuildFilterExpression(property, secondFilterValue, secondFilterOperator, row.Type);
|
||||
innerFilterExpressions.Add(secondFilterExpression);
|
||||
}
|
||||
|
||||
@@ -2016,13 +2051,14 @@ namespace Radzen.Blazor
|
||||
/// <summary>
|
||||
/// Builds a filter expression for a property and value.
|
||||
/// </summary>
|
||||
private CompositeFilterDescriptor BuildFilterExpression(string property, object value, FilterOperator filterOperator)
|
||||
private CompositeFilterDescriptor BuildFilterExpression(string property, object value, FilterOperator filterOperator, Type type)
|
||||
{
|
||||
return new CompositeFilterDescriptor
|
||||
{
|
||||
Property = property,
|
||||
FilterValue = value,
|
||||
FilterOperator = filterOperator
|
||||
FilterOperator = filterOperator,
|
||||
Type = type
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ var forwardingOptions = new ForwardedHeadersOptions()
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||
};
|
||||
forwardingOptions.KnownNetworks.Clear();
|
||||
forwardingOptions.KnownIPNetworks.Clear();
|
||||
forwardingOptions.KnownProxies.Clear();
|
||||
|
||||
app.UseForwardedHeaders(forwardingOptions);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ErrorOnDuplicatePublishOutputFiles>False</ErrorOnDuplicatePublishOutputFiles>
|
||||
<UserSecretsId>d4f5f92a-c1c5-47b2-bb94-becc7f09133c</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RadzenBlazorDemos\RadzenBlazorDemos.csproj" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.*-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OData" Version="9.*-*" />
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="2.20.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>cf316844-9d34-42f9-a2a7-72a167736c64</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RadzenBlazorDemos.Host\RadzenBlazorDemos.Host.csproj" />
|
||||
<ProjectReference Include="..\RadzenBlazorDemos\RadzenBlazorDemos.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<RadzenTabs SelectedIndex=@selectedIndex Change="@OnTabChange">
|
||||
<Tabs>
|
||||
<RadzenTabsItem Text=".NET 8 & 9">
|
||||
<RadzenTabsItem Text=".NET 10 & 9 & 8">
|
||||
<div class="rz-py-0 rz-py-sm-4 rz-px-0 rz-px-sm-2 rz-px-lg-12">
|
||||
<RadzenAlert AlertStyle="AlertStyle.Info" Variant="Variant.Flat" Shade="Shade.Lighter" AllowClose="false" class="rz-mb-12">
|
||||
All interactive features of the Radzen Blazor components require interactivity of the container <code>.razor</code> file to be enabled or the <code>@@rendermode</code>
|
||||
@@ -27,7 +27,7 @@ attribute of the component to be set to one of the following values: <code>Inter
|
||||
More info is available in the <RadzenLink Text="rendering mode article" Path="https://learn.microsoft.com/en-us/aspnet/core/blazor/components/render-modes?view=aspnetcore-8.0" target="_blank" /> from the official Blazor documentation.
|
||||
</RadzenAlert>
|
||||
<RadzenAlert AlertStyle="AlertStyle.Info" Variant="Variant.Flat" Shade="Shade.Lighter" AllowClose="false" class="rz-mb-12">
|
||||
If you have upgraded your application to .NET 8 or .NET 9 follow the getting started instructions for the version you initially used - e.g.
|
||||
If you have upgraded your application to .NET 8 .NET 9 or .NET 10 follow the getting started instructions for the version you initially used - e.g.
|
||||
<RadzenLink Path="get-started/net7-server" Text=".NET 7" /> or <RadzenLink Path="get-started/net6-server" Text=".NET 6"/>.
|
||||
These instructions assume the new application layout which uses rendering modes and was introduced with .NET 8.
|
||||
</RadzenAlert>
|
||||
|
||||
161
RadzenBlazorDemos/Pages/PivotDataGridDynamicData.razor
Normal file
161
RadzenBlazorDemos/Pages/PivotDataGridDynamicData.razor
Normal file
@@ -0,0 +1,161 @@
|
||||
@using System
|
||||
@using System.Collections.Generic
|
||||
@using System.Linq
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
@inherits RadzenBlazorDemos.Shared.DbContextPage
|
||||
|
||||
<RadzenCard Variant="Variant.Outlined" class="rz-my-4">
|
||||
<RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" Style="margin:1rem">
|
||||
<RadzenSwitch @bind-Value="@showColumnTotals" Name="ShowColumnTotals" />
|
||||
<RadzenLabel Text="Show column totals" Component="ShowColumnTotals" />
|
||||
<RadzenSwitch @bind-Value="@showRowTotals" Name="ShowRowTotals" />
|
||||
<RadzenLabel Text="Show row totals" Component="ShowRowTotals" />
|
||||
<RadzenSwitch @bind-Value="@allowDrillDown" Name="AllowDrillDown" />
|
||||
<RadzenLabel Text="Allow drill-down" Component="AllowDrillDown" />
|
||||
<RadzenSwitch @bind-Value="@allowPaging" Name="AllowPaging" />
|
||||
<RadzenLabel Text="Allow paging" Component="AllowPaging" />
|
||||
<RadzenDropDown @bind-Value="@pagerPosition"
|
||||
Visible="@allowPaging"
|
||||
TextProperty="Text"
|
||||
ValueProperty="Value"
|
||||
Data="@(Enum.GetValues(typeof(PagerPosition)).Cast<PagerPosition>().Select(t => new { Text = $"{t}", Value = t }))" />
|
||||
</RadzenStack>
|
||||
<RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" Style="margin:1rem">
|
||||
<RadzenSwitch @bind-Value="@allowFieldsPicking" Name="AllowFieldsPicking" />
|
||||
<RadzenLabel Text="Allow fields picking" Component="AllowFieldsPicking" />
|
||||
<RadzenSwitch @bind-Value="@allowSorting" Name="AllowSorting" Visible="@allowFieldsPicking" />
|
||||
<RadzenLabel Text="Allow sorting" Component="AllowSorting" Visible="@allowFieldsPicking" />
|
||||
<RadzenSwitch @bind-Value="@allowFiltering" Name="AllowFiltering" Visible="@allowFieldsPicking" />
|
||||
<RadzenLabel Text="Allow filtering" Component="AllowFiltering" Visible="@allowFieldsPicking" />
|
||||
</RadzenStack>
|
||||
</RadzenCard>
|
||||
|
||||
<RadzenPivotDataGrid Data="@data"
|
||||
TItem="IDictionary<string, object>"
|
||||
AllowSorting="@allowSorting"
|
||||
AllowFiltering="@allowFiltering"
|
||||
AllowDrillDown="@allowDrillDown"
|
||||
AllowFieldsPicking="@allowFieldsPicking"
|
||||
ShowColumnsTotals="@showColumnTotals"
|
||||
ShowRowsTotals="@showRowTotals"
|
||||
AllowPaging="@allowPaging"
|
||||
PagerPosition="@pagerPosition"
|
||||
PageSize="20"
|
||||
AllowAlternatingRows="true"
|
||||
GridLines="Radzen.DataGridGridLines.Default"
|
||||
Style="height: 700px;">
|
||||
<Columns>
|
||||
@foreach (var field in columnFields)
|
||||
{
|
||||
<RadzenPivotColumn @key="@field.Property"
|
||||
Title="@field.Title"
|
||||
Width="@field.Width"
|
||||
Type="@field.Type"
|
||||
Property="@PropertyAccess.GetDynamicPropertyExpression(field.Property, field.Type)" />
|
||||
}
|
||||
</Columns>
|
||||
<Rows>
|
||||
@foreach (var field in rowFields)
|
||||
{
|
||||
<RadzenPivotRow @key="@field.Property"
|
||||
Title="@field.Title"
|
||||
Type="@field.Type"
|
||||
Property="@PropertyAccess.GetDynamicPropertyExpression(field.Property, field.Type)" />
|
||||
}
|
||||
</Rows>
|
||||
<Aggregates>
|
||||
@foreach (var aggregate in aggregateFields)
|
||||
{
|
||||
<RadzenPivotAggregate @key="@aggregate.Property"
|
||||
Title="@aggregate.Title"
|
||||
Type="@aggregate.Type"
|
||||
Property="@PropertyAccess.GetDynamicPropertyExpression(aggregate.Property, aggregate.Type)"
|
||||
Aggregate="@aggregate.Aggregate"
|
||||
FormatString="@aggregate.FormatString"
|
||||
TextAlign="@aggregate.TextAlign" />
|
||||
}
|
||||
</Aggregates>
|
||||
</RadzenPivotDataGrid>
|
||||
|
||||
@code {
|
||||
private readonly IReadOnlyList<PivotFieldDescriptor> columnFields = new[]
|
||||
{
|
||||
new PivotFieldDescriptor("OrderYear", "Order Year", typeof(int?), "140px"),
|
||||
new PivotFieldDescriptor("ShipCountry", "Ship Country", typeof(string), "180px")
|
||||
};
|
||||
|
||||
private readonly IReadOnlyList<PivotFieldDescriptor> rowFields = new[]
|
||||
{
|
||||
new PivotFieldDescriptor("Category", "Category", typeof(string)),
|
||||
new PivotFieldDescriptor("Product", "Product", typeof(string))
|
||||
};
|
||||
|
||||
private readonly IReadOnlyList<PivotAggregateDescriptor> aggregateFields = new[]
|
||||
{
|
||||
new PivotAggregateDescriptor("TotalSales", "Total Sales", typeof(double), AggregateFunction.Sum, "{0:C}", TextAlign.Right),
|
||||
new PivotAggregateDescriptor("Quantity", "Quantity", typeof(int), AggregateFunction.Sum, "{0:N0}", TextAlign.Right),
|
||||
new PivotAggregateDescriptor("Discount", "Average Discount", typeof(double), AggregateFunction.Average, "{0:P1}", TextAlign.Right),
|
||||
new PivotAggregateDescriptor("UnitPrice", "Average Unit Price", typeof(double), AggregateFunction.Average, "{0:C}", TextAlign.Right)
|
||||
};
|
||||
|
||||
private List<IDictionary<string, object>> data = new List<IDictionary<string, object>>();
|
||||
private bool allowDrillDown = true;
|
||||
private bool allowFieldsPicking = true;
|
||||
private bool allowSorting = true;
|
||||
private bool allowFiltering = true;
|
||||
private bool allowPaging = true;
|
||||
private bool showColumnTotals = true;
|
||||
private bool showRowTotals = true;
|
||||
private PagerPosition pagerPosition = PagerPosition.Bottom;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
var sales = await (from od in dbContext.OrderDetails
|
||||
join o in dbContext.Orders on od.OrderID equals o.OrderID
|
||||
join p in dbContext.Products on od.ProductID equals p.ProductID
|
||||
join c in dbContext.Categories on p.CategoryID equals c.CategoryID
|
||||
select new
|
||||
{
|
||||
CategoryName = c.CategoryName,
|
||||
ProductName = p.ProductName,
|
||||
OrderYear = o.OrderDate.HasValue ? o.OrderDate.Value.Year : 0,
|
||||
ShipCountry = o.ShipCountry,
|
||||
UnitPrice = od.UnitPrice ?? 0,
|
||||
Quantity = od.Quantity ?? 0,
|
||||
Discount = od.Discount ?? 0,
|
||||
TotalAmount = (od.UnitPrice ?? 0) * (od.Quantity ?? 0) * (1 - (od.Discount ?? 0))
|
||||
}).ToListAsync();
|
||||
|
||||
data = sales.Select(result =>
|
||||
{
|
||||
var row = new Dictionary<string, object>
|
||||
{
|
||||
["OrderYear"] = result.OrderYear,
|
||||
["ShipCountry"] = string.IsNullOrEmpty(result.ShipCountry) ? "Unknown" : result.ShipCountry,
|
||||
["Category"] = result.CategoryName ?? "(no category)",
|
||||
["Product"] = result.ProductName ?? "(no product)",
|
||||
["Quantity"] = result.Quantity,
|
||||
["UnitPrice"] = result.UnitPrice,
|
||||
["Discount"] = result.Discount,
|
||||
["TotalSales"] = result.TotalAmount
|
||||
};
|
||||
|
||||
return (IDictionary<string, object>)row;
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
|
||||
private sealed record PivotFieldDescriptor(string Property, string Title, Type Type, string? Width = null);
|
||||
|
||||
private sealed record PivotAggregateDescriptor(string Property,
|
||||
string Title,
|
||||
Type Type,
|
||||
AggregateFunction Aggregate,
|
||||
string? FormatString,
|
||||
TextAlign TextAlign);
|
||||
}
|
||||
|
||||
20
RadzenBlazorDemos/Pages/PivotDataGridDynamicDataPage.razor
Normal file
20
RadzenBlazorDemos/Pages/PivotDataGridDynamicDataPage.razor
Normal file
@@ -0,0 +1,20 @@
|
||||
@page "/pivot-data-grid-dynamic"
|
||||
|
||||
<RadzenText TextStyle="TextStyle.H2" TagName="TagName.H1" class="rz-pt-8">
|
||||
PivotDataGrid <strong>dynamic</strong> data support
|
||||
</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P" class="rz-pb-4">
|
||||
Schema-less datasets are common when data comes from external APIs. This demo shows how to build a pivot table on top of
|
||||
<code>IDictionary<string, object></code> records without defining C# models.
|
||||
</RadzenText>
|
||||
|
||||
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.P" class="rz-pb-4">
|
||||
The example generates 200 rows with dynamic columns (year, region, category, product, quantity, unit price, discount, total sales) and uses
|
||||
<code>PropertyAccess.GetDynamicPropertyExpression</code> to configure pivot rows, columns, and aggregates at runtime while enabling totals, drill-down,
|
||||
filtering, sorting, and field picking.
|
||||
</RadzenText>
|
||||
|
||||
<RadzenExample ComponentName="PivotDataGrid" Example="PivotDataGridDynamicData">
|
||||
<PivotDataGridDynamicData />
|
||||
</RadzenExample>
|
||||
|
||||
@@ -7,23 +7,23 @@
|
||||
|
||||
<RadzenCard Variant="Variant.Outlined" class="rz-my-4">
|
||||
<RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" Style="margin:1rem">
|
||||
<RadzenSwitch @bind-Value=@showColumnsTotals Name="ShowColumnsTotals" TValue="bool" />
|
||||
<RadzenSwitch @bind-Value=@showColumnsTotals Name="ShowColumnsTotals" />
|
||||
<RadzenLabel Text="Show columns totals" Component="ShowColumnsTotals" />
|
||||
<RadzenSwitch @bind-Value=@showRowsTotals Name="ShowRowsTotals" TValue="bool" />
|
||||
<RadzenSwitch @bind-Value=@showRowsTotals Name="ShowRowsTotals" />
|
||||
<RadzenLabel Text="Show rows totals" Component="ShowRowsTotals" />
|
||||
<RadzenSwitch @bind-Value=@allowDrillDown Name="AllowDrillDown" TValue="bool" />
|
||||
<RadzenSwitch @bind-Value=@allowDrillDown Name="AllowDrillDown" />
|
||||
<RadzenLabel Text="Allow drill-down" Component="AllowDrillDown" />
|
||||
<RadzenSwitch @bind-Value=@allowPaging Name="AllowPaging" TValue="bool" />
|
||||
<RadzenSwitch @bind-Value=@allowPaging Name="AllowPaging" />
|
||||
<RadzenLabel Text="AllowPaging" Component="AllowPaging" />
|
||||
<RadzenDropDown @bind-Value="@pagerPosition" Visible="@allowPaging" TextProperty="Text" Name="PagerPosition" ValueProperty="Value"
|
||||
Data="@(Enum.GetValues(typeof(PagerPosition)).Cast<PagerPosition>().Select(t => new { Text = $"{t}", Value = t }))" />
|
||||
</RadzenStack>
|
||||
<RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center" Style="margin:1rem">
|
||||
<RadzenSwitch @bind-Value=@allowFieldsPicking Name="AllowFieldsPicking" TValue="bool" />
|
||||
<RadzenSwitch @bind-Value=@allowFieldsPicking Name="AllowFieldsPicking" />
|
||||
<RadzenLabel Text="Allow fields picking" Component="AllowFieldsPicking" />
|
||||
<RadzenSwitch @bind-Value=@allowSorting Name="AllowSorting" TValue="bool" Visible=@allowFieldsPicking />
|
||||
<RadzenSwitch @bind-Value=@allowSorting Name="AllowSorting" Visible=@allowFieldsPicking />
|
||||
<RadzenLabel Text="Allow sorting" Component="AllowSorting" Visible=@allowFieldsPicking />
|
||||
<RadzenSwitch @bind-Value=@allowFiltering Name="AllowFiltering" TValue="bool" Visible=@allowFieldsPicking />
|
||||
<RadzenSwitch @bind-Value=@allowFiltering Name="AllowFiltering" Visible=@allowFieldsPicking />
|
||||
<RadzenLabel Text="Allow filtering" Component="AllowFiltering" Visible=@allowFieldsPicking />
|
||||
</RadzenStack>
|
||||
</RadzenCard>
|
||||
|
||||
@@ -25,7 +25,7 @@ The Radzen.Blazor library provides a built-in service that persists the current
|
||||
</RadzenText>
|
||||
<RadzenTabs SelectedIndex=@selectedIndex Change="@OnTabChange">
|
||||
<Tabs>
|
||||
<RadzenTabsItem Text=".NET 8">
|
||||
<RadzenTabsItem Text=".NET 8 & 9 & 10">
|
||||
@RegisterService
|
||||
@MainLayout
|
||||
<RadzenText TextStyle="TextStyle.H6" TagName="TagName.H3" class="rz-mt-12 rz-mb-4">3. Open the <code>App.razor</code> file of your application and add this code:</RadzenText>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Radzen.Blazor" Version="*" Condition="'$(Configuration)' == 'Release'" />
|
||||
<ProjectReference Include="..\Radzen.Blazor\Radzen.Blazor.csproj" Condition="'$(Configuration)' != 'Release'" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.*-*" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.*-*" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.*-*" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.Extensions" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Razor" Version="6.0.10" />
|
||||
|
||||
@@ -1036,6 +1036,14 @@ namespace RadzenBlazorDemos
|
||||
Tags = new [] { "pivot", "crosstab", "analysis", "aggregation", "drill-down", "datagrid", "table", "query", "IQueryable" }
|
||||
},
|
||||
new Example
|
||||
{
|
||||
Name = "Dynamic data",
|
||||
Path = "/pivot-data-grid-dynamic",
|
||||
Title = "Blazor Pivot DataGrid Component - dynamic data sets | Free UI Components by Radzen",
|
||||
Description = "Bind RadzenPivotDataGrid to schema-less IDictionary<string, object> records and configure fields dynamically.",
|
||||
Tags = new [] { "pivot", "dynamic", "dictionary", "analysis", "aggregation", "drill-down", "datagrid", "table" }
|
||||
},
|
||||
new Example
|
||||
{
|
||||
Name = "OData",
|
||||
Path = "/pivot-data-grid-odata",
|
||||
|
||||
Reference in New Issue
Block a user