使用 Blazor 将输入文本动态绑定到类/对象属性

Posted

技术标签:

【中文标题】使用 Blazor 将输入文本动态绑定到类/对象属性【英文标题】:Dynamically binding input-text to class/object propertys using Blazor 【发布时间】:2020-06-04 23:15:24 【问题描述】:

我正在尝试使用 Blazor 为类中的属性构建输入字段的动态列表,但无法弄清楚如何将输入框的内容绑定/链接到类的属性。 (该类可以有大量的公共属性,不仅仅是下面例子中的名称和描述,它们并不总是“字符串”类型)

假设我有这个类/模型:

public class customer
        public string Name  get; set; 
        public int Age  get; set; 
        public string Description  get; set; 


我得到了这个 blazor 组件(updateC.razor):

@inherits CLogic    
@if (nfo != null)

      @foreach (var obj in nfo)
      
             <input type="text" class="form-control"      
             bind=@SCustomer.GetType().GetProperty(obj.ToString())/>
      

最后是 Clogic:

public class Clogic: ComponentBase
    [Parameter]
    public Customer SCustomer  get; set;  = new Customer();
    [Parameter]
    public PropertyInfo[] nfo  get; set; 

    protected override void OnAfterRender(bool firstRender)
    
        if (firstRender)
        
            nfo = SCustomer.GetType().GetProperties();
            StateHasChanged();
        
    

这是假设将每个输入字段中所做的更改绑定到当前 SCustomer 实例中的正确属性(输入时,假设更新类/对象的正确属性) .这不起作用,SCustomer 内部的值在输入完成后不会更改。我猜我完全错了,但似乎无法弄清楚如何使这项工作,也找不到任何这样做的例子。

【问题讨论】:

【参考方案1】:
@foreach (var propertyInfo in nfo)

    <input type="text" class="form-control"      
    value="@propertyInfo.GetValue(SCustomer)" 
    @onchange="@((ChangeEventArgs __e) =>
       propertyInfo.SetValue(SCustomer, __e.Value.ToString()))" />

【讨论】:

这可能缺少一个结束括号并给出以下错误:“System.Reflection.TargetParameterCountException: 'Parameter count mismatch.'” 值得注意的是客户类的公共道具并不总是类型字符串。 (我会尝试更新问题以便提及)。 “文本”类型的输入值始终是一个字符串。切换属性类型并根据类型创建其他类型的输入。 我找到了一种方法,虽然它有点丑,但我自己的回答。谢谢你的帮助!它指导了我很多。另外,如果您在这个问题上有比我更好的工作解决方案,请发布它,我一定会接受它!【参考方案2】:
@foreach(propertyInfo in nfo)

  <label>@propertyInfo.Name</label>
  <input type="text" value="@propertyInfo.GetValue(SCustomer)" @onchange="@((ChangeEventArgs __e) => 
    propertyInfo.SetValue(SCustomer,Convert.ChangeType(__e.Value, 
    propertyInfo.PropertyType,null))"/>

【讨论】:

【参考方案3】:

我终于找到了一种方法,这是我的解决方案: 我创建了一个助手类:

public class PropHolder
    
        [Parameter]
        public PropertyInfo info  get; set; 
        [Parameter]
        public string type  get; set; 
        public PropHolder(PropertyInfo nfo, string propType)
        
            info = nfo;
            type = propType;
        
    

然后我创建了这个类的字典和一些检查函数(这是在 Clogic 内部)

[Parameter]
        public Dictionary<int, PropHolder> Props get; set; 
        public void GetAllProps()
        
            Props = new Dictionary<int, PropHolder>();
            //nfo = SCustomer.GetType().GetProperties();
            int Cid = 0;
            foreach (PropertyInfo pif in SCustomer.GetType().GetProperties())
            
                Props[Cid] = new PropHolder(pif, pif.PropertyType.Name);
                Cid++;
            
        

        public string CheckName(PropHolder propertyInfo)
        
            if (propertyInfo.GetType() == typeof(PropHolder))
            
                return propertyInfo.type;
            
            else
            
                return propertyInfo.GetType().Name.ToString();
            

        
        public PropertyInfo getInfo(PropHolder propertyInfo)
        
            if (propertyInfo.GetType() == typeof(PropHolder))
            
                return propertyInfo.info;
            
            else
            
                return null;
            
        

最后我能够遍历我的字典的键并正确绑定所有值(从“来自火星的 agua”给出的答案中得到了很多帮助来解决这个问题) 这是 updateC.razor 内容:

@if (Props != null)
        

            @foreach (int key in Props.Keys)
            

                var pinfo = Props[key];
                @if (CheckName(pinfo) == "String")
                
                    <input type="text" class="form-control" value=@(getInfo(pinfo).GetValue(SCustomer)) @onchange="@((ChangeEventArgs __e) => getInfo(pinfo).SetValue(SCustomer, __e.Value.ToString()))" />
                
            
        

这为每个字符串类型的道具提供了一个输入框,如果要处理其他类型,现在可以轻松添加它。这可能不是最好的解决方案,但它确实有效。如果发布任何更好的工作解决方案,我会更新答案。

【讨论】:

【参考方案4】:

我使用泛型解决了这个问题。这让每个输入类型都传递一个泛型类型,该泛型类型定义了它想要使用的类型。

<input @bind="Name.Value" />
<input @bind="Age.Value" />

<div><code>Name</code>: @Name.Value</div>
<div><code>Age</code>: @Age.Value</div>

@code 
    private FormField<string> Name  get; set;  = new FormField<string>();
    private FormField<int> Age  get; set;  = new FormField<int>();

    public class Form
    
        public ICollection<IFormField> Fields  get; set; 
    

    public interface IFormField
    
        public int ControlType  get; set; 
    

    public class FormField<T> : IFormField
    
        public int ControlType  get; set; 
        public T Value  get; set; 
    

它在 BlazorFiddle 上:https://blazorfiddle.com/s/wen1g26q

【讨论】:

以上是关于使用 Blazor 将输入文本动态绑定到类/对象属性的主要内容,如果未能解决你的问题,请参考以下文章

Kivy,Python3.5 - 将用户文本输入绑定到类中的方法

XAML:将文本框最大长度绑定到类常量

如何将字典结果绑定到类对象c#linq

如何在 Blazor 项目中使用 C# 绑定制作 HTML 文本多行?

Blazor 复选框绑定不起作用 - 服务器端

如何使用react-js以动态形式将复选框值与文本输入绑定?