You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将动态生成对象的值绑定到DynamicComponent?

问题描述

我有一个在运行时生成类型的对象,还有一个自定义的DynamicComponent组件,它有一个名为Value的参数,我想将生成对象的属性绑定到该参数。如果在运行前知道类型,我会使用@bind-Value,或者Value="@MyObject.Value"和ValueChanged="@(v => MyObject.Value = v)"。

目前遇到的问题:DynamicComponent的Value初始值设置正确,组件修改值时onChangeEvent能成功触发,但外部修改form的Value后,组件不会随之更新。怀疑是因为GetValue(Instance)返回的是Value的副本。

实验代码(Razor部分)

@foreach (FormInput input in form.Inputs)
{
    <DynamicComponent Type="@input.InputType" Parameters="@input.Parameters" />
}

@code
{
    private Form form;

    private string inputName = string.Empty;

    protected override void OnInitialized()
    {
        InputAttribute reqAttribute = new()
        {
            Type = typeof(RequiredAttribute),
            ConstructorArguments = Array.Empty<object>()
        };

        FormInput input = new()
        {
            InputType = typeof(TsInputText),
            ReturnType = typeof(string),
            Attributes = new() { reqAttribute }
        };
        inputName = input.Id;

        Dictionary<string, object> parameters = new();
        parameters.Add("Label", "Test");
        parameters.Add("PropertyName", input.Id);

        input.Parameters = parameters;

        List<FormInput> inputs = new() { input };

        form = new(inputs);

        form.BindProperty(input, "Value");
    }
}

Form类代码(C#)

public Type Model { get; private set; }

public object Instance { get; private set; }

public List<FormInput> Inputs { get; set; }

public Form(IEnumerable<FormInput> inputs)
{
    // Model is generated here. 
    // Model has a property named input.Id for each input in the inputs argument.
    
    // Instance of the Model type is instantiated here
}

public void BindProperty(FormInput input, string inputParameter)
{
    input.Parameters.Add(inputParameter, GetPropertyInfo(Model, input.Id).GetValue(Instance));
    
    EventCallback<string> onChangeEvent = EventCallback.Factory.Create<string>(this, s => SetProperty(input.Id, s));
    input.Parameters.Add($"{inputParameter}Changed", onChangeEvent);
}

解决方案

问题核心是值类型的副本传递:GetValue(Instance)返回的是值类型的副本(比如string、int),存入Parameters字典后,外部修改form.Instance的属性时,Parameters里的旧值不会自动同步,DynamicComponent也就不会更新。以下是两种可行方案:

方案一:手动同步Parameters(简单直接)

每次外部修改form.Instance的属性后,手动更新对应FormInput的Parameters字典,并触发组件重新渲染。

给Form类添加同步方法:

public void SyncInputValue(FormInput input, string inputParameter)
{
    // 更新Parameters中的Value为最新值
    input.Parameters[inputParameter] = GetPropertyInfo(Model, input.Id).GetValue(Instance);
}

外部修改属性后,执行以下操作:

// 假设获取到对应的FormInput实例
var targetInput = form.Inputs.First(i => i.Id == inputName);
form.SyncInputValue(targetInput, "Value");
// 触发组件重新渲染,让DynamicComponent读取新值
StateHasChanged();

方案二:用包装类实现引用传递(自动同步)

通过引用类型的包装类,让Parameters存储引用而非值类型副本,外部修改包装类内部值时,组件能直接读取最新值。

  1. 定义通用包装类:
public class ValueWrapper<T>
{
    public T Value { get; set; }
}
  1. 修改Form类的模型生成逻辑:
    将原本的属性类型(如string)替换为ValueWrapper<string>,确保生成的Model中每个属性都是包装类类型。

  2. 调整BindProperty方法:

public void BindProperty(FormInput input, string inputParameter)
{
    var propertyInfo = GetPropertyInfo(Model, input.Id);
    var wrapper = propertyInfo.GetValue(Instance) as ValueWrapper<string>;
    
    // 存入包装类的Value(后续可通过引用直接更新)
    input.Parameters.Add(inputParameter, wrapper.Value);
    
    // 修改回调,直接更新包装类的内部值
    EventCallback<string> onChangeEvent = EventCallback.Factory.Create<string>(this, s => 
    {
        wrapper.Value = s;
        SetProperty(input.Id, s); // 保留原有业务逻辑
    });
    input.Parameters.Add($"{inputParameter}Changed", onChangeEvent);
}
  1. 外部修改属性时:
var propertyInfo = form.GetPropertyInfo(form.Model, inputName);
var wrapper = propertyInfo.GetValue(form.Instance) as ValueWrapper<string>;
wrapper.Value = "外部修改的新值";
// 触发组件渲染,让UI更新
StateHasChanged();

注意事项

  • 两种方案都需要调用StateHasChanged()触发组件重新渲染,否则UI不会更新。
  • 方案一适合简单场景,实现成本低;方案二更适合频繁同步的场景,减少手动同步的代码量。

内容的提问来源于stack exchange,提问作者Torin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:38:12