如何创建可复用Blazor Radzen DataGrid自定义组件及错误解决
问题描述
需要创建可复用的Blazor Radzen DataGrid组件,支持基于任意类动态渲染数据。以Customer类和DummyData模拟数据为例,尝试封装CustomDataGrid组件时遇到编译错误,错误信息如下:
Severity Code Description Project File Line Suppression State Details Error (active) CS1061 'RadzenDataGridColumn<Customer>' does not contain a definition for 'AddAttribute' and no accessible extension method 'AddAttribute' accepting a first argument of type 'RadzenDataGridColumn<Customer>' could be found (are you missing a using directive or an assembly reference?) TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 32 Error (active) CS0103 The name 'OnUpdateRow' does not exist in the current context TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 6 Error (active) CS0103 The name 'AddNewCustomer' does not exist in the current context TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 8 Error (active) CS1643 Not all code paths return a value in lambda expression of type 'RenderFragment<RadzenDataGridColumn<Customer>>' TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 29 Error (active) CS1061 'RadzenDataGridColumn<Customer>' does not contain a definition for 'OpenComponent' and no accessible extension method 'OpenComponent' accepting a first argument of type 'RadzenDataGridColumn<Customer>' could be found (are you missing a using directive or an assembly reference?) TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 31 Error (active) CS1061 'RadzenDataGridColumn<Customer>' does not contain a definition for 'CloseComponent' and no accessible extension method 'CloseComponent' accepting a first argument of type 'RadzenDataGridColumn<Customer>' could be found (are you missing a using directive or an assembly reference?) TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 35 Error (active) CS1061 'RadzenDataGridColumn<Customer>' does not contain a definition for 'AddAttribute' and no accessible extension method 'AddAttribute' accepting a first argument of type 'RadzenDataGridColumn<Customer>' could be found (are you missing a using directive or an assembly reference?) TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 34 Error (active) CS1061 'RadzenDataGridColumn<Customer>' does not contain a definition for 'AddAttribute' and no accessible extension method 'AddAttribute' accepting a first argument of type 'RadzenDataGridColumn<Customer>' could be found (are you missing a using directive or an assembly reference?) TestingDynamicEditableTable D:\etc\Practice\TestingDynamicEditableTable\TestingDynamicEditableTable\Pages\Counter.razor 33
现有基础代码
DummyData.cs
using Bogus; using System; using System.Collections.Generic; namespace TestingDynamicEditableTable.Data { public static class DummyData { private static readonly Faker<Customer> CustomerFaker = new Faker<Customer>() .RuleFor(c => c.CustomerID, f => f.Random.AlphaNumeric(5)) .RuleFor(c => c.CompanyName, f => f.Company.CompanyName()) .RuleFor(c => c.ContactName, f => f.Person.FullName); public static IEnumerable<Customer> GetCustomers(int count = 50) { return CustomerFaker.Generate(count); } } }
解决方案
1. 重构可复用CustomDataGrid组件
采用插槽式设计传递自定义列,封装通用编辑、删除、新增逻辑,暴露必要事件供调用页处理业务逻辑:
@typeparam TItem @using Radzen <RadzenDataGrid @ref="DataGridRef" TItem="TItem" AllowPaging="true" PageSize="5" AllowSorting="true" EditMode="@EditMode" AllowGrouping="true" AllowColumnResize="true" Data="@Items" ColumnWidth="200px" RowUpdate="@RowUpdate" RowCreate="@RowCreate"> <Columns> <!-- 接收调用页传递的自定义列 --> @ChildContent <!-- 通用操作列(编辑/删除/保存/取消) --> <RadzenDataGridColumn TItem="TItem" Context="item" Filterable="false" Sortable="false" TextAlign="TextAlign.Right" Frozen="true" FrozenPosition="FrozenColumnPosition.Right"> <Template Context="item"> <RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(() => EditRow(item))" @onclick:stopPropagation="true" /> <RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@(() => DeleteRow(item))" /> </Template> <EditTemplate Context="item"> <RadzenButton Icon="save" ButtonStyle="ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(() => SaveRow(item))" /> <RadzenButton Icon="cancel" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@(() => CancelEdit(item))" /> </EditTemplate> </RadzenDataGridColumn> </Columns> </RadzenDataGrid> @code { [Parameter] public IEnumerable<TItem> Items { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } // 自定义列插槽 [Parameter] public EventCallback<TItem> RowUpdate { get; set; } [Parameter] public EventCallback<TItem> RowCreate { get; set; } [Parameter] public EventCallback<TItem> RowDelete { get; set; } [Parameter] public DataGridEditMode EditMode { get; set; } = DataGridEditMode.Single; public RadzenDataGrid<TItem> DataGridRef { get; set; } private TItem _editingItem; public void EditRow(TItem item) { _editingItem = item; DataGridRef.EditRow(item); } public async Task SaveRow(TItem item) { await DataGridRef.UpdateRow(item); } public void CancelEdit(TItem item) { _editingItem = default; DataGridRef.CancelEditRow(item); } public void InsertRow(TItem item) { DataGridRef.InsertRow(item); } public async Task DeleteRow(TItem item) { await RowDelete.InvokeAsync(item); DataGridRef.Reload(); } }
2. 修改Counter.razor使用复用组件
在调用页中传递自定义列,实现业务相关的事件逻辑:
@page "/counter" @using TestingDynamicEditableTable.Data @using System.Collections.Generic @using System.Linq @using Radzen <CustomDataGrid TItem="Customer" Items="@customers" RowUpdate="@OnUpdateRow" RowCreate="@OnCreateRow" RowDelete="@OnDeleteRow" @ref="customGrid"> <!-- 自定义列定义,保留原有编辑模板 --> <RadzenDataGridColumn TItem="Customer" Property="CustomerID" Title="ID" Width="40px" Frozen="true" /> <RadzenDataGridColumn TItem="Customer" Property="CompanyName" Title="Company Name" Width="280px"> <EditTemplate Context="customer"> <RadzenTextBox @bind-Value="customer.CompanyName" Style="width:100%" /> </EditTemplate> </RadzenDataGridColumn> <RadzenDataGridColumn TItem="Customer" Property="ContactName" Title="Contact Name" Width="220px"> <EditTemplate Context="customer"> <RadzenTextBox @bind-Value="customer.ContactName" Style="width:100%" /> </EditTemplate> </RadzenDataGridColumn> </CustomDataGrid> <RadzenButton Text="Add New Customer" Click="AddNewCustomer" /> @code { private CustomDataGrid<Customer> customGrid; private List<Customer> customers; private Customer _editingCustomer; protected override void OnInitialized() { customers = DummyData.GetCustomers().ToList(); } private void AddNewCustomer() { var newCustomer = new Customer(); customers.Add(newCustomer); customGrid.InsertRow(newCustomer); } private async Task OnUpdateRow(Customer customer) { // 实现数据更新逻辑(比如调用API保存) _editingCustomer = null; } private async Task OnCreateRow(Customer customer) { // 实现数据新增逻辑 } private async Task OnDeleteRow(Customer customer) { customers.Remove(customer); } }
错误原因说明
- 原代码误用
RenderFragment<RadzenDataGridColumn<TItem>>类型,正确方式是使用RenderFragment作为插槽传递列内容 - 修改后的
Counter.razor中注释掉了事件处理方法,导致编译报错,需恢复完整实现 - 手动构建
RenderFragment时混淆了RenderTreeBuilder方法与组件实例方法,OpenComponent等是RenderTreeBuilder的API,不能直接调用组件实例的该方法
内容的提问来源于stack exchange,提问作者Duane Scheepers
相关产品推荐
相关产品推荐

