.NET Core 3.1 Blazor应用中Radzen数据网格动态FilterTemplate的FilterValue父子双向绑定问题
你当前的实现遇到的核心问题是:CascadingParameter默认是单向传递的,当你在子组件的RadzenDropDown中使用@bind-Value="FilterValue"时,修改的只是子组件内部的FilterValue副本,并不会同步回父级的colDef.FilterValue。下面给你两种可靠的解决方案:
方案一:使用引用类型包装FilterValue(推荐)
因为值类型的参数传递是拷贝,而引用类型传递的是引用,我们可以把FilterValue包装成一个简单的类,这样子组件修改包装类的属性时,父级的对象会自动同步。
步骤1:定义包装类
public class FilterValueWrapper<T> { public T Value { get; set; } }
步骤2:修改colDef的FilterValue类型
确保你的colDef里的FilterValue是FilterValueWrapper<string>类型(根据你的实际值类型调整泛型参数):
// 假设你的colDef是类似这样的类 public class ColumnDefinition { public string Property { get; set; } public FilterValueWrapper<string> FilterValue { get; set; } = new FilterValueWrapper<string>(); public RenderFragment FilterTemplate { get; set; } // 其他属性... }
步骤3:更新父组件的Grid列代码
<RadzenDataGridColumn Property="@colDef.Property" FilterValue="@colDef.FilterValue.Value" > <FilterTemplate> <CascadingValue Value="@colDef.FilterValue"> @colDef.FilterTemplate </CascadingValue> </FilterTemplate> </RadzenDataGridColumn>
步骤4:修改子组件的代码
<RadzenDropDown TValue="string" @bind-Value="FilterValueWrapper.Value" Data="@DrpData" TextProperty="@DrpTextProperty" ValueProperty="@DrpValueProperty" > </RadzenDropDown> @code { [CascadingParameter] public FilterValueWrapper<string> FilterValueWrapper { get; set; } [Parameter] public string DrpTextProperty { get; set; } [Parameter] public string DrpValueProperty { get; set; } [Parameter] public IEnumerable<DrpDataType> DrpData { get; set; } }
这样当你在下拉框选择值时,修改的是FilterValueWrapper.Value,这个变更会直接同步到父级的colDef.FilterValue.Value,RadzenDataGrid也能正确获取到过滤值。
方案二:使用EventCallback传递变更
如果你不想修改FilterValue的类型,可以通过EventCallback让子组件通知父级更新FilterValue。
步骤1:修改子组件,添加EventCallback参数
<RadzenDropDown TValue="string" Value="@FilterValue" ValueChanged="@OnValueChanged" Data="@DrpData" TextProperty="@DrpTextProperty" ValueProperty="@DrpValueProperty" > </RadzenDropDown> @code { [CascadingParameter] public string FilterValue { get; set; } [Parameter] public EventCallback<string> FilterValueChanged { get; set; } [Parameter] public string DrpTextProperty { get; set; } [Parameter] public string DrpValueProperty { get; set; } [Parameter] public IEnumerable<DrpDataType> DrpData { get; set; } private async Task OnValueChanged(string newValue) { await FilterValueChanged.InvokeAsync(newValue); } }
步骤2:更新父组件的列代码,绑定FilterValueChanged
<RadzenDataGridColumn Property="@colDef.Property" FilterValue="@colDef.FilterValue" > <FilterTemplate> @{ var currentColDef = colDef; } @colDef.FilterTemplate(FilterValueChanged: (value) => { currentColDef.FilterValue = value; return Task.CompletedTask; }) </FilterTemplate> </RadzenDataGridColumn>
这里需要注意,因为RenderFragment的参数传递特性,我们需要捕获当前的colDef到局部变量,避免闭包陷阱。
为什么原代码不生效?
原代码中CascadingParameter传递的是值类型(string),Blazor会创建一个副本给子组件。当子组件修改这个副本时,父级的原始值不会受到任何影响,所以变更无法同步回去。而引用类型的传递是引用地址,修改其内部属性会直接反映到父级的对象上。
内容的提问来源于stack exchange,提问作者AnC Dev

