C# Blazor:是否可以使用反射按名称将泛型项绑定到属性?

C# Blazor:是否可以使用反射按名称将泛型项绑定到属性?,c#,reflection,binding,blazor,C#,Reflection,Binding,Blazor,我正在尝试使用Blazor获得一个通用编辑器模板,该模板绑定到通过反射找到的属性,如下所示: @typeparam TItem @foreach (var propertyName in FieldsList) { <div> <InputText id="name" @bind-Value="@getBindProperty(propertyName)" /> </div> } @f

我正在尝试使用Blazor获得一个通用编辑器模板,该模板绑定到通过反射找到的属性,如下所示:

@typeparam TItem

@foreach (var propertyName in FieldsList) {
    <div>
        <InputText id="name" @bind-Value="@getBindProperty(propertyName)" />
    </div>
}

@functions {
    [Parameter]
    public TItem ItemEditModel { get; set; }

    public string[] FieldsList {
        get {
            // get all properties decorated with some custom attribute...
            return typeof(TItem).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(MyCustomAttribute))).Select(x => x.Name).ToArray();
        }
    }

    public string getBindProperty(string propName) {
        return string.Format("{0}.{1}", nameof(ItemEditModel), propName);
    }
}
@foreach (var propertyName in FieldsList) {
    <div>
        <InputText id="name" @bind-Value="@myContextObject.StrValues[propertyName]" />
    </div>
}
@typeparam-TItem
@foreach(FieldsList中的var propertyName){
}
@功能{
[参数]
公共滴度ItemEditModel{get;set;}
公共字符串[]字段列表{
得到{
//获取使用某些自定义属性修饰的所有属性。。。
返回typeof(TItem).GetProperties()。其中(prop=>Attribute.IsDefined(prop,typeof(MyCustomAttribute)))。选择(x=>x.Name).ToArray();
}
}
公共字符串getBindProperty(字符串propName){
返回string.Format(“{0}.{1}”,nameof(ItemEditModel),propName);
}
}
不接受上述内容,因为赋值的左侧必须是变量、属性或索引器

所以我不能通过属性名绑定到属性,所以我继续尝试其他语法,比如

<InputText id="name" @bind-Value="ItemEditModel.propertyName" />

这也不被接受,因为TItem不包含“propertyName”的定义

所有这些都是有意义的——但关键的问题是——是否需要对此做些什么,或者是否不可能通过名称将控件绑定到属性

奖金问题:
如果确实可以这样做,是否有一种方法可以根据属性类型进行切换(通常,只有基本类型,如'string´、'DateTime´、'int´、'double´、'bool´……?

如果使用InputText Blazor的组件,则应使用EditForm Blazor的组件对其进行包装

另一种方法可能如下。 @typeparam滴度

    @foreach (var propertyName in FieldsList)
    {
       <div>
          <input @bind="PropertyVars[propertyName]" />
       </div>
    }

    <button type="button" @onclick="OnSubmit">Reset</button>

    @code {
        [Parameter]
        public TItem ItemEditModel { get; set; }

       public Dictionary<string, string> PropertyVars { get; set; } = new 
     Dictionary<string, string>();

   protected override void OnInitialized()
   {
     foreach (var propertyName in FieldsList)
     {
        var propertyInfo = ItemEditModel.GetType().GetProperty(propertyName);
        PropertyVars.Add(propertyName, 
        propertyInfo?.GetValue(ItemEditModel).ToString());
     }

  }

  public string[] FieldsList
  {
    get
    {
        return typeof(TItem).GetProperties().Select(x => x.Name).ToArray();
    }
  }

  private void OnSubmit()
  {
    var tt = PropertyVars;

    foreach (var propertyName in FieldsList)
    {
        var propertyInfo = ItemEditModel.GetType().GetProperty(propertyName);

        var uu = PropertyVars[propertyName].GetType();

        if (uu == propertyInfo?.PropertyType)
        {
            propertyInfo.SetValue(ItemEditModel, 
            Convert.ChangeType(PropertyVars[propertyName], propertyInfo.PropertyType),
            null);
        }

    }

    var yy = ItemEditModel;
 }
}
@foreach(FieldsList中的var propertyName)
{
}
重置
@代码{
[参数]
公共滴度ItemEditModel{get;set;}
公共字典属性vars{get;set;}=new
字典();
受保护的覆盖无效OnInitialized()
{
foreach(FieldsList中的var propertyName)
{
var propertyInfo=ItemEditModel.GetType().GetProperty(propertyName);
添加(propertyName,
propertyInfo?.GetValue(ItemEditModel.ToString());
}
}
公共字符串[]字段列表
{
得到
{
返回typeof(TItem).GetProperties().Select(x=>x.Name).ToArray();
}
}
私有void OnSubmit()
{
var tt=不动产var;
foreach(FieldsList中的var propertyName)
{
var propertyInfo=ItemEditModel.GetType().GetProperty(propertyName);
var uu=PropertyVars[propertyName].GetType();
if(uu==propertyInfo?.PropertyType)
{
propertyInfo.SetValue(ItemEditModel,
Convert.ChangeType(PropertyVars[propertyName],propertyInfo.PropertyType),
无效);
}
}
var yy=ItemEditModel;
}
}

总结我最终得到的解决方案:

  • 我创建了索引属性类包装器,允许我访问值(请注意,我还创建了另外两个只读和可写的包装器,以防万一)

    公共类索引属性{
    只读操作SetAction;
    只读函数GetFunc;
    公共IndexedProperty(Func getFunc,Action setAction){
    this.GetFunc=GetFunc;
    this.SetAction=SetAction;
    }
    公共TValue this[TIndex i]{
    得到{
    返回GetFunc(i);
    }
    设置{
    设置动作(i,值);
    }
    }
    }
    公共类ReadOnlyIndexedProperty{
    只读函数GetFunc;
    公共只读索引属性(Func getFunc){
    this.GetFunc=GetFunc;
    }
    公共TValue this[TIndex i]{
    得到{
    返回GetFunc(i);
    }
    }
    }
    公共类WriteOnlyIndexedProperty{
    只读操作SetAction;
    public WriteOnlyIndexedProperty(操作集操作){
    this.SetAction=SetAction;
    }
    公共TValue this[TIndex i]{
    设置{
    设置动作(i,值);
    }
    }
    }
    
  • 我创建了一个“BindableBase”对象,我的所有对象都从该对象继承,其中我添加了index属性:

    IndexedProperty<string, string> _strValues;
    [JsonIgnore]
    public IndexedProperty<string, string> StrValues {
      get {
        if (_strValues == null) {
          _strValues = new IndexedProperty<string, string>(GetStrValue, SetStrValue);
        }
        return _strValues;
      }
    }
    
    private string GetStrValue(string propName) {
      // use reflection here to get the property value as string
      // --- NOTE: beware of performance here I suggest you take a look at related link
    }
    
    private void SetStrValue(string propName, string value) {
      // use reflection here to SET the property value from string
      // --- NOTE: beware of performance here I suggest you take a look at related link
    }
    
    索引属性值;
    [JsonIgnore]
    公共索引属性值{
    得到{
    如果(_strValues==null){
    _strValues=新的IndexedProperty(GetStrValue,SetStrValue);
    }
    返回正确值;
    }
    }
    私有字符串GetStrValue(字符串propName){
    //在此处使用反射以字符串形式获取属性值
    //---注意:注意这里的性能我建议你看看相关链接
    }
    私有void SetStrValue(字符串propName、字符串值){
    //在此处使用反射设置字符串的属性值
    //---注意:注意这里的性能我建议你看看相关链接
    }
    
  • 检查性能对您是否重要

  • 在我的表单中,我使用索引属性进行绑定,如下所示:

    @typeparam TItem
    
    @foreach (var propertyName in FieldsList) {
        <div>
            <InputText id="name" @bind-Value="@getBindProperty(propertyName)" />
        </div>
    }
    
    @functions {
        [Parameter]
        public TItem ItemEditModel { get; set; }
    
        public string[] FieldsList {
            get {
                // get all properties decorated with some custom attribute...
                return typeof(TItem).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(MyCustomAttribute))).Select(x => x.Name).ToArray();
            }
        }
    
        public string getBindProperty(string propName) {
            return string.Format("{0}.{1}", nameof(ItemEditModel), propName);
        }
    }
    
    @foreach (var propertyName in FieldsList) {
        <div>
            <InputText id="name" @bind-Value="@myContextObject.StrValues[propertyName]" />
        </div>
    }
    
    @foreach(FieldsList中的var propertyName){
    }
    

  • @copycar_am和.

    这实际上是在创建一个“缓冲区”,在完成后存储/检索这些值,这当然是一个不错的方法。。。你知道这是否可以直接绑定到原始对象吗?好的,基于你的anser,我在基类中添加了一个属性indexor,它返回与上面相同的结果-这让整个魔法发挥了作用。谢谢你的主意!在这里分享另一个有用的资源,为这里的一个非常有用的技巧提供奖励:@neggenbe欢迎您。很高兴能提供帮助,谢谢你的链接,非常感谢helpfull@neggenbe难道你不想用你的结局来回答你自己的问题吗?我发现自己正在尝试做类似的事情。PS:很抱歉格式化,无法正确检测代码。。。