资讯动态

ASP.NET Core Blazor QuickGrid 组件实战指南:分页、排序、过滤与虚拟化数据表格

发布时间:2026/9/10 13:53:18 来源:尧图企业网站定制
ASP.NET Core Blazor QuickGrid 组件实战指南分页、排序、过滤与虚拟化数据表格【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcoreMicrosoft.AspNetCore.Components.QuickGrid是 ASP.NET Core 为 Blazor 提供的高性能数据表格组件用于覆盖最常见的网格渲染场景。本文以其官方包文档PACKAGE.md为核心骨架结合dotnet/aspnetcore仓库中的真实源码QuickGrid.razor.cs、Columns、Pagination 等逐层展开帮助你掌握组件如何接入、内置分页/排序/虚拟化的完整参数体系、IQueryable/ EF Core / 远程数据源三种数据供给方式以及组件底层的数据请求与竞态处理原理。读完本文你将能直接在一个真实的 Blazor 应用里落地一个可排序、可分页、可虚拟化甚至对接任意远程 API 的数据网格。什么是 QuickGridQuickGrid 是随Microsoft.AspNetCore.Components.QuickGridNuGet 包分发的 Blazor 数据表格组件。按照包文档的定位它为常见的网格渲染场景提供简单、便捷的数据网格组件见 PACKAGE.md。官方列出的核心能力包括分页Pagination过滤Filtering排序Sorting虚拟化Virtualization同时支持内存IQueryable、EF CoreIQueryable与远程数据源可配置的列属性可自定义的样式与自研表格相比它把查询数据 → 排序 → 分页 → 渲染这条链路抽象成组件自身的行为开发者只需声明数据源与列表格渲染、排序指示器、页码同步等脏活全部交给组件处理。从源码上看QuickGridTGridItem最终渲染为一个原生 HTMLtable并通过classquickgrid提供默认样式挂钩见 QuickGrid.razor.cs 的GridClass()方法——表格 class 由quickgrid、用户传入的Class以及数据加载期间的loading标记拼接而成。也就是说它是零第三方依赖、构建在 Blazor 原语之上的组件。快速上手安装与注册在你的 Blazor 项目中通过 NuGet 安装与包文档中的安装命令一致dotnet add package Microsoft.AspNetCore.Components.QuickGrid安装完成后在需要使用网格的页面或全局_Imports.razor中加入命名空间引用using Microsoft.AspNetCore.Components.QuickGrid如果希望在 EF Core 场景下获得异步查询能力详见下文EF Core 数据源小节还需要安装配套适配器包dotnet add package Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter说明仓库内 QuickGrid 本体工程位于 Microsoft.AspNetCore.Components.QuickGrid.csprojEF Core 适配器工程位于 Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter.csproj。最小可运行示例用内存数据演示最常见的用法——直接把IQueryableT绑定到Items参数再声明若干PropertyColumn即可QuickGrid Items_people PropertyColumn Property(p p.Id) TitleID / PropertyColumn Property(p p.Name) Title姓名 / PropertyColumn Property(p p.BirthDate) Title生日 Formatyyyy-MM-dd / /QuickGrid code { private sealed record Person(int Id, string Name, DateTime BirthDate); private IQueryablePerson _people new[] { new Person(1, 张三, new DateTime(1990, 1, 1)), new Person(2, 李四, new DateTime(1995, 5, 20)), new Person(3, 王五, new DateTime(1988, 11, 11)), }.AsQueryable(); }注意PropertyColumn的Property参数被标注为[Parameter, EditorRequired]必须传入一个ExpressionFuncTGridItem, TProp见 PropertyColumn.cs。组件会编译该表达式求值并渲染单元格文本。从源码PropertyColumn.cs可以看到若你没有显式设置Title当表达式主体是成员访问如p p.Name时组件会自动以成员名Name作为列标题因此上面的示例省略Title同样可以工作。核心类型全景包文档的 Main Types 章节列出了一组围绕QuickGridTGridItem协同工作的公开类型这里逐一结合源码说明它们各自的角色类型角色QuickGridTGridItem渲染网格的表格组件本体类型参数TGridItem表示每一行数据的类型声明见 QuickGrid.razor.csPropertyColumnTGridItem,TProp单元格显示单一值的列绑定属性表达式可选Format格式化TemplateColumnTGridItem单元格渲染自定义模板的列可自由输出任意 MarkupPaginator为PaginationState提供翻页 UI 的组件PaginationState表示QuickGridTGridItem分页状态的可观察模型GridSortTGridItem网格内的排序规则描述可组合多级排序GridItemsProviderTGridItem为网格提供数据的回调委托除文档列举的公开类型外仓库还暴露了支撑数据供给协议的类型请求描述GridItemsProviderRequestTGridItem、结果封装GridItemsProviderResultTGridItem、异步查询抽象IAsyncQueryExecutor以及排序方向枚举SortDirection。列Column体系所有列都继承自抽象基类ColumnBaseTGridItemColumnBase.razor.cs。基类统一提供下列可配置属性Title列标题文本不使用HeaderTemplate时自动渲染。Class作用于表头/表体单元格的可选 CSS 类。Align表头与单元格内容的对齐方式。从 QuickGrid.razor.cs 的对齐处理看枚举取值包括Align.Start、Align.Center、Align.End、Align.Left、Align.Right分别映射为col-justify-start/col-justify-center等内部样式类。HeaderTemplate自定义表头模板不设置时默认渲染Title、排序指示与列选项按钮。ColumnOptions列头部的选项 UI片段。设置后表头默认会出现弹出选项的按钮代码通过QuickGridTGridItem.ShowColumnOptionsAsync/HideColumnOptionsAsync控制其开关这两个方法定义在 QuickGrid.razor.cs。Sortable是否允许按该列排序null时按列类型决定默认值。InitialSortDirectionIsDefaultSortColumn声明默认排序列与其方向。PlaceholderTemplate虚拟化时数据尚未加载的占位内容。SortBy该列的排序规则抽象属性由具体列类型实现。Grid当前列所在网格实例的引用。两种具体列的实现差异PropertyColumn更聪明。当传入Format时源码会先校验值类型是否实现IFormattable包括可空类型的底层类型否则抛出InvalidOperationException见 PropertyColumn.cs。同时它内部自动构造一个升序GridSortTGridItem作为默认排序规则。也正因如此它的SortBy是只读的——尝试在PropertyColumn上赋值SortBy会抛出NotSupportedException错误信息明确提示需要自定义排序规则时请使用TemplateColumn见 PropertyColumn.cs。TemplateColumn则把渲染完全交给你的ChildContent模板RenderFragmentTGridItem模板内可通过隐式context变量访问当前行数据。它覆写IsSortableByDefault()只要指定了SortBy就默认可排序且SortBy是可由用户赋值的公开参数见 TemplateColumn.cs。QuickGrid Items_people PropertyColumn Property(p p.Name) / TemplateColumn Title年龄 context.Age 岁 /TemplateColumn TemplateColumn Title操作 button classbtn btn-sm btn-primary onclick() ViewDetail(context)详情/button /TemplateColumn /QuickGrid数据供给三种数据源模式QuickGridTGridItem通过两个互斥的参数接收数据Items与ItemsProvider。从 QuickGrid.razor.cs 可以看出规则很严格——同时指定两者会抛出InvalidOperationException两者都为null时则渲染空网格返回空集与总数为 0见 QuickGrid.razor.cs。1. 内存 IQueryable内存集合通过Enumerable.AsQueryable()转成IQueryableT后交给Items。此时排序、分页的Skip/Take全部在 LINQ to Objects 上执行适合中小规模数据QuickGrid Items_orders Pagination_pagination ItemKey(o o.Id) PropertyColumn Property(o o.Id) Title订单号 / PropertyColumn Property(o o.Customer) Title客户 / PropertyColumn Property(o o.Total) Title金额 FormatC / /QuickGrid Paginator State_pagination /2. EF Core IQueryable直接把DbContext的DbSetT作为Items传入排序与分页会下推为数据库端的 SQL 执行QuickGrid Items_forecasts PropertyColumn Property(f f.Date) / PropertyColumn Property(f f.TemperatureC) / /QuickGrid code { [Inject] WeatherDbContext Db { get; set; } default!; private IQueryableWeatherForecast? _forecasts; protected override void OnInitialized() _forecasts Db.Forecasts; }这里有一个值得注意的性能细节IQueryable只暴露同步查询 APIQuickGrid 内部设计了一个适配器IAsyncQueryExecutor用来调用可用的异步查询 API源码注释原话见 QuickGrid.razor.cs。该接口定义在 IAsyncQueryExecutor.cs只有三个方法IsSupportedT、CountAsyncT、ToArrayAsyncT。如果不注册任何适配器网格会退化为同步执行Items.Count()与result.ToArray()见 QuickGrid.razor.cs会阻塞请求线程EF Core 场景推荐安装Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter并在Program.cs的服务容器中注册其提供的扩展方法实现在 EntityFrameworkAdapterServiceCollectionExtensions.cs执行器实现在 EntityFrameworkAsyncQueryExecutor.cs之后网格会通过AsyncQueryExecutorSupplier.GetAsyncQueryExecutor(Services, Items)自动探测并使用 EF Core 的异步计数与物化 API。3. 远程数据源ItemsProvider当数据来自 Web API、第三方服务等无法表达为IQueryable的远端时使用委托GridItemsProviderTGridItemGridItemsProvider.cs。网格向你的委托传入一个GridItemsProviderRequestTGridItem结构体GridItemsProviderRequest.cs其中包含四个关键字段StartIndex请求片段的起始下标零基分页/虚拟化时由网格计算好。Count本次最多返回多少条null表示不限制。SortByColumn/SortByAscending当前排序列与方向。CancellationToken请求被新请求取代时可取消的令牌。委托需要返回GridItemsProviderResultTGridItemGridItemsProviderResult.cs由必填的Items与TotalItemCount组成。其中TotalItemCount的语义是过滤后全部可用条目数——若网格分页它必须覆盖所有页若虚拟化必须覆盖整个滚动范围用于渲染总行数与页码。官方提供了静态方法GridItemsProviderResult.From(items, totalItemCount)做类型推断免去重复书写泛型参数。QuickGrid TGridItemProduct ItemsProviderLoadProductsAsync /private async ValueTaskGridItemsProviderResultProduct LoadProductsAsync(GridItemsProviderRequestProduct request) { var queryUrl $/api/products?start{request.StartIndex}count{request.Count} $sort{...}ascending{request.SortByAscending}; var response await Http.GetFromJsonAsyncProductQueryResult(queryUrl); return GridItemsProviderResult.From(response.Items, response.TotalCount); }如果 Provider 内部使用IQueryableGridItemsProviderRequest还提供了两个工具方法ApplySorting(source)直接把当前列的GridSort应用到查询上GetSortByProperties()则返回一组(属性名, 方向)对方便你拼接到远程查询串中见 GridItemsProviderRequest.cs。需要手动触发重新查询时例如外部条件变化调用网格的RefreshDataAsync()定义于 QuickGrid.razor.cs。排序PropertyColumn 的内置规则与 GridSort 多级排序排序是 QuickGrid 开箱即用的核心能力对PropertyColumn默认即可按属性排序点击表头升/降序切换对TemplateColumn只要提供SortBy就启用排序。GridSortTGridItemGridSort.cs是排序规则的载体其静态工厂与链式方法可以组合出复杂的多级排序GridSortTGridItem.ByAscending(expr)/.ByDescending(expr)指定第一排序键.ThenAscending(expr)/.ThenDescending(expr)追加次级排序键。一个姓氏升序、名字升序的复合排序可以这样写QuickGrid Items_people TemplateColumn Title姓名 SortBy_nameSort (${context.LastName}, {context.FirstName}) /TemplateColumn /QuickGrid code { private static readonly GridSortPerson _nameSort GridSortPerson.ByAscending(p p.LastName) .ThenAscending(p p.FirstName); }两个底层事实值得了解在点击表头翻转向导时QuickGrid.SortByColumnAsync通过NavigationManager.GetUriWithQueryParameters把排序写入 URL默认查询参数名为sort与direction取值asc/desc见 QuickGrid.razor.cs。也就是说QuickGrid 的排序、页码都是可分享、可刷新保留的 URL 状态而不是仅存于组件内存。GridSort内部会把表达式树翻译成可序列化的属性名列表ToPropertyList供 URL 状态/GetSortByProperties使用。翻译只支持简单的成员访问表达式如x x.Medals.Gold会得到Medals.Gold遇到复杂表达式会抛出异常提示文案见 GridSort.cs。仓库的测试用例 GridSortTest.cs 对这套行为有系统覆盖。默认排序列通过两个列参数声明进入页面时的默认排序PropertyColumn Property(p p.Price) IsDefaultSortColumntrue InitialSortDirectionSortDirection.Descending /源码里网格会先收集列、再发第一次数据请求目的就是为了在加载数据前应用默认排序或列选项避免做一次注定被重排的无用查询相关注释见 QuickGrid.razor.cs 与AddColumn中对默认排序列的处理。分页PaginationState Paginator分页由两个对象协作完成状态模型PaginationState与UI 组件Paginator。PaginationStatePaginationStatePaginationState.cs是可独立于网格存在的普通 C# 对象通常放在code或 DI 容器中供网格与分页 UI 共享。其公开成员成员说明ItemsPerPage每页条目数默认 10可在初始化时直接赋值CurrentPageIndex当前页索引零基通过SetCurrentPageIndexAsync修改TotalItemCount跨页总条目数在关联网格加载完数据前为nullLastPageIndex最后一页的零基索引TotalItemCount未知前为null派生自(TotalItemCount - 1) / ItemsPerPageSetCurrentPageIndexAsync(int)切换页码并通知关联网格重新拉取渲染数据初始化private PaginationState _pagination new PaginationState { ItemsPerPage 20 };然后把同一实例同时绑定给网格的Pagination参数和页面里的PaginatorQuickGrid Items_people Pagination_pagination * columns * /QuickGrid Paginator State_pagination /组件内部通过事件订阅把PaginationState的变化转译为重新查询PaginationState暴露CurrentPageItemsChanged事件QuickGrid在OnParametersSetAsync中订阅该事件QuickGrid.razor.cs一旦页码/每页条数/总条数的GetHashCode()发生变化即触发重查哈希组合方式见 PaginationState.cs。值得注意的健壮性设计当底层数据因过滤而减少、导致当前页超出范围时PaginationState会在更新TotalItemCount的同时自动跳转到最后一个合法页并触发数据重载PaginationState.cs避免用户停留在空页上。PaginatorPaginatorPaginator.razor.cs渲染「上一页 / 页码 / 下一页 / 末页」等翻页 UI。它的两个参数State必填要绑定的PaginationStateSummaryTemplate可选的共 N 条汇总模板。Paginator与QuickGrid共享同一套 URL 状态机制页码以?pageNURL 中 1 基、内部 0 基写入地址栏通过NavigationManager.LocationChanged监听前进/后退/分享链接并同步页码见 Paginator.razor.cs。自定义 URL 查询参数名页码默认page、排序列默认sort、排序方向默认direction的查询参数名可通过QuickGrid的QueryParameterNameOptions参数整体定制参数说明见 QuickGrid.razor.cs类型定义在同目录 QueryParameterNameOptions.cs。QuickGrid Items_people Pagination_pagination QueryParameterNameOptions_queryOptions / code { private QueryParameterNameOptions _queryOptions new() { Page p, // ?p2 Sort orderBy, // orderByName Direction dir, // dirasc }; }虚拟化处理海量数据的滚动渲染对于几千行乃至更多的大表QuickGrid 通过参数Virtualizetrue启用虚拟化只渲染当前滚动视口附近的数据能显著改善滚动性能。虚拟化相关参数如下全部定义见 QuickGrid.razor.cs参数默认值说明Virtualizefalse是否启用虚拟化通常配合外部滚动容器使用ItemSize50每行的期望高度像素虚拟化机制据此计算该取多少条数据并保持滚动准确OverscanCount3视口上下额外预渲染的行数调大可减少滚动时的渲染频次更平滑但会增加首屏加载量InitialItemIndex0首次交互渲染时定位到的行零基仅在网格首次获知条目数时应用一次AnchorModeVirtualizeAnchorMode.Start视口锚定模式控制新数据到达时列表边缘的行为[Experimental(ASP0030)]实验特性ItemComparerEqualityComparerT.Default数据加载之间用于判断条目是前插还是后增的比较器实验特性。对无值相等语义的引用类型默认实现会退化为引用比较数据源每次返回新实例时可能产生误判因此建议按稳定主键提供比较器ItemKeyx x行级key选择器设置为稳定唯一标识如主键后即便TGridItem实例被新查询替换行元素与数据的关联也能保持RowClass—每行渲染时回调返回行级 CSS 类OnRowClick—行点击回调EventCallbackTGridItem典型配置示例QuickGrid ItemsProviderLoadTelemetryAsync Virtualizetrue ItemSize36 OverscanCount5 ItemKey(r r.Id) TGridItemTelemetryRecord PropertyColumn Property(r r.Id) / PropertyColumn Property(r r.Timestamp) / PropertyColumn Property(r r.Message) / /QuickGrid虚拟化的底层机制从 QuickGrid.razor.cs 可以看到虚拟化的实现并非自研滚动逻辑而是把负载委托给 Blazor 内置的Virtualize(int, TGridItem)组件——行数据被包装为(行号, 数据)元组行号用于填充无障碍aria-rowindex数据加载通过Virtualize.RefreshDataAsync()触达内部的ProvideVirtualizedItemsQuickGrid.razor.cs该方法对请求做了100ms 防抖源码注释称这能消除滚动时大量冗余查询代价是交互后略有延迟见 QuickGrid.razor.cs分页与虚拟化可叠加计算片段时会把PaginationState的偏移量叠加进StartIndex并把请求数量裁剪到当前页剩余范围内需要编程式滚动时调用ScrollToItemAsync(itemIndex, cancellationToken)该方法仅在使用虚拟化且网格已渲染时有效否则抛出InvalidOperationExceptionQuickGrid.razor.cs。虚拟化要求每一行渲染为固定的相同高度否则滚动位置会失准。如果数据量不大或已经启用分页文档与源码注释都建议不要开启虚拟化见Virtualize参数的 XML 注释。过滤在数据层实现还是借助列选项PACKAGE.md 将过滤列为核心特性之一。需要澄清的是QuickGrid核心组件本身不内置搜索输入框过滤通常发生在数据层IQueryable或ItemsProvider内。由于过滤条件改变后网格需要重新查询所以典型做法是让Items/Provider 依赖页面的搜索状态并用RefreshDataAsync()驱动重查div classmb-2 input bind_searchText bind:eventoninput placeholder按姓名搜索… classform-control / /div QuickGrid Items_filteredPeople ref_grid PropertyColumn Property(p p.Name) / /QuickGrid code { private QuickGridPerson? _grid; private string _searchText ; private IQueryablePerson _allPeople ...; private IQueryablePerson _filteredPeople string.IsNullOrWhiteSpace(_searchText) ? _allPeople : _allPeople.Where(p p.Name.Contains(_searchText)); }而在 UI 层面QuickGrid 提供的过滤入口是列选项面板Column Options若某列设置了ColumnOptionsRenderFragment其表头会出现一个按钮点击后通过ShowColumnOptionsAsync弹出选项 UIQuickGrid.razor.cs你可以在面板内放置复选框、下拉框等将筛选条件接入数据供给逻辑。快速过滤控件类型如小于/大于/包含需要自行结合 Provider 实现。可访问性与竞态处理源码级细节ARIA网格依据当前列与方向输出aria-sortascending/descending/none见 QuickGrid.razor.cs虚拟化时aria-rowcount按整个滚动范围/当前页概念行数计算而不是物理tr数量相关注释见 QuickGrid.razor.cs。竞态处理网格对每次数据加载都建立独立的CancellationTokenSource发起新加载前先取消上一次仍在挂起的请求后发请求胜出避免旧响应覆盖新状态QuickGrid.razor.cs。仓库中的 GridRaceConditionTest.cs 专门针对这类并发场景做了回归验证。JS 互操作首次渲染后组件会加载内嵌的./_content/Microsoft.AspNetCore.Components.QuickGrid/QuickGrid.razor.js模块用于列选项面板的定位、自动聚焦以及文档级事件监听QuickGrid.razor.cs如果客户端已断开连接DisposeAsync会以JSDisconnectedException安全路径清理。样式定制样式层面有三处挂钩QuickGrid的Class参数追加到渲染出的table的 class 上与内置quickgrid类并存。ColumnBase.Class与Align作用于特定列。Theme参数默认为default决定命中哪些样式规则见 QuickGrid.razor.cs。仓库提供了两套现成样式组件基样式写在 QuickGrid.razor.cssCSS 隔离样式默认主题定义在 Themes/Default.css。你既可以依赖默认外观直接使用也可以在项目中引入一份自定义 CSS利用quickgrid及其列对齐/排序态 class如col-sort-asc、col-sort-desc、col-justify-center等覆盖出符合产品风格的表格。小结与阅读路线QuickGrid 的定位是覆盖常见网格场景的默认方案数据供给抽象成Items/ItemsProvider两条互斥通道排序、分页、虚拟化既是组件行为又通过 URL 查询参数获得可书签化、可分享的状态EF Core 通过IAsyncQueryExecutor适配器获得异步执行能力对竞态、防抖、ARIA 等细节的处理使其可以直接用于生产。如果想继续深入推荐按以下路径阅读仓库源码组件主体与全部公开参数QuickGrid.razor.cs列模型与排序规则Columns 目录ColumnBase.razor.cs、PropertyColumn.cs、TemplateColumn.cs、GridSort.cs分页状态机与翻页 UIPagination 目录Provider 请求/响应协议GridItemsProvider.cs 与 GridItemsProviderRequest.csEF Core 异步适配EntityFrameworkAsyncQueryExecutor.cs行为测试test 目录排序、竞态场景均有用例覆盖包的官方文档全文见 PACKAGE.md它是本文所有核心功能清单的最初出处。【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价