| File: Utils\MaxItemCountHelper.cs | Web Access |
| Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Linq.Expressions; using System.Reflection; using Microsoft.AspNetCore.Components.Web.Virtualization; using Microsoft.FluentUI.AspNetCore.Components; namespace Aspire.Dashboard.Utils; // Temporary work around to set MaxItemCount on Virtualize component via reflection. // Required because dashboard currently targets .NET 8 and MaxItemCount isn't available. // // ASP.NET Core issue: https://github.com/dotnet/aspnetcore/issues/63651 // Note that this work around should be left in place for a while after the issue is fixed in ASP.NET Core. // .NET 9 needs to be patched, and users may have unpatched versions of .NET 9 on their machines for a while. public static class VirtualizeHelper<TItem> { private static readonly Func<Virtualize<TItem>, int>? s_getMaxItemCount = CreateGetter(); private static readonly Action<Virtualize<TItem>, int>? s_setMaxItemCount = CreateSetter(); private static Func<Virtualize<TItem>, int>? CreateGetter() { var type = typeof(Virtualize<TItem>); var prop = type.GetProperty("MaxItemCount", BindingFlags.Instance | BindingFlags.Public); if (prop == null || !prop.CanRead) { return null; } var instance = Expression.Parameter(type, "virtualize"); var body = Expression.Property(instance, prop); return Expression.Lambda<Func<Virtualize<TItem>, int>>(body, instance).Compile(); } private static Action<Virtualize<TItem>, int>? CreateSetter() { var type = typeof(Virtualize<TItem>); var prop = type.GetProperty("MaxItemCount", BindingFlags.Instance | BindingFlags.Public); if (prop == null || !prop.CanWrite) { return null; } var instance = Expression.Parameter(type, "virtualize"); var valueParam = Expression.Parameter(typeof(int), "value"); var body = Expression.Assign(Expression.Property(instance, prop), valueParam); return Expression.Lambda<Action<Virtualize<TItem>, int>>(body, instance, valueParam).Compile(); } public static bool TrySetMaxItemCount(Virtualize<TItem> virtualize, int max) { if (s_getMaxItemCount == null || s_setMaxItemCount == null) { return false; } if (s_getMaxItemCount(virtualize) == max) { return false; } s_setMaxItemCount(virtualize, max); return true; } } public static class FluentDataGridHelper<TGridItem> { private static readonly Func<FluentDataGrid<TGridItem>, Virtualize<(int, TGridItem)>>? s_getVirtualize = CreateGetter(); private static Func<FluentDataGrid<TGridItem>, Virtualize<(int, TGridItem)>>? CreateGetter() { var type = typeof(FluentDataGrid<TGridItem>); var field = type.GetField("_virtualizeComponent", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return null; } var instance = Expression.Parameter(type, "dataGrid"); var body = Expression.Convert(Expression.Field(instance, field), typeof(Virtualize<(int, TGridItem)>)); return Expression.Lambda<Func<FluentDataGrid<TGridItem>, Virtualize<(int, TGridItem)>>> (body, instance).Compile(); } private static Virtualize<(int, TGridItem)>? GetVirtualize(FluentDataGrid<TGridItem> dataGrid) => s_getVirtualize?.Invoke(dataGrid); public static bool TrySetMaxItemCount(FluentDataGrid<TGridItem> dataGrid, int max) { var virtualize = GetVirtualize(dataGrid); if (virtualize == null) { return false; } return VirtualizeHelper<(int, TGridItem)>.TrySetMaxItemCount(virtualize, max); } }