【问题标题】:How to use @bind-Value in a dynamic form?如何以动态形式使用@bind-Value?
【发布时间】:2020-05-16 23:54:51
【问题描述】:

我正在使用 Blazor 从我的模型的属性创建一个动态表单。

我正在使用for each 循环来遍历模型的属性。

public class SensorType
{
    public int Id { get; set; }
    [Required]
    [MaxLength(30)]
    [Display(Name = "Sensor Type Name")]
    public string Name { get; set; }
    [Required]
    [MaxLength(500)]
    public string Description { get; set; }
    [Required]
    [MaxLength(2048)]
    [Display(Name = "Datasheet URL")]
    public string DatasheetUrl { get; set; }
}

我实现了这个剃刀视图,我尝试绑定到public SensorType sensortype { get; set; }。但我需要绑定到 sensortype.property,其中 property 是模型在 for each 循环中具有的任何属性。但我不能简单地打电话说@bind-Value="sensortype.property"。关于如何做到这一点的任何想法?我不想手动输入每个字段。谢谢!

<EditForm Model="@sensortype" OnValidSubmit="@SaveSensorType">

@foreach(var property in typeof(SensorType).GetProperties())
{
    if(property.Name == "Id")
    {
        continue;
    }
    <div class="form-group row">
        <label class="col-sm-2 col-form-label">@(GetAttribute(property, false)) </label> //This function get the name of the property in a human-readable way.
        <div class="col-sm-10">//I would like to bind here to sensortype's property in the for each loop but sensortype.property gives me an error.
            <InputTextArea class="form-control" @bind-Value="sensortype.property" value="sensortype.property.Name" placeholder="Description of the Type of Sensor" /> 
        </div>
    </div>
}

【问题讨论】:

  • 你不应该那样做……而且你不能那样做。 FieldIdentifier 仅支持对象的简单成员访问器(字段、属性)。 "sensortype.property" 没有意义。没有这样的东西......你会得到一个错误。
  • 是的,sensor.property 是没有意义的,但它只是为了让我知道如果它有意义的话我想做什么。

标签: c# asp.net asp.net-core blazor blazor-server-side


【解决方案1】:

这几天我在玩 blazor,我制作了一种 DynamicForm,虽然不完美,但可以正常工作。我只是想向您展示我的动态形式作为概念证明,而不是我将在生产中使用的东西。

基本上我们想写这样的东西:

<DynamicForm @bind-Model="MySensorType" /> 

//this will generate a form with fields for all properties of the model

因此,在索引视图中,让我们为 MySensorType 创建一个属性和一些标记,以查看在编辑表单字段时模型是否正在更改。

@page "/"

    <div style="display:flex">
        <div> 
            <DynamicForm @bind-Model="MySensorType" />
        </div>

        <div style="background:yellow;flex:1;margin:20px;">
            <p>Id: @MySensorType.Id</p>
            <p>Name: @MySensorType.Name</p>
            <p>Description: @MySensorType.Description</p>
            <p>Url: @MySensorType.DatasheetUrl</p>
        </div>
    </div>

@code {
    public SensorType MySensorType { get; set; } = new SensorType();


    public class SensorType
    {
        public int Id { get; set; } = 1;
        public string Name { get; set; } = "Some Name";
        public string Description { get; set; } = "Some Description";
        public string DatasheetUrl { get; set; } = "This is a URL";
    }
} 

为了自动生成字段,我们需要某种动态字段。 下面的组件用于命名为“DynamicField”

    <div>
        <label>@Caption</label>
        @if (Value is String sValue)
        {
            <input type="text" value="@sValue" @onchange="OnChange"/>
        }
        @if (Value is int iValue)
        {
            <input type="number" value="@iValue" @onchange="OnChange" />
        }

    </div>

@code {
    [Parameter] public string Caption { get; set; }
    [Parameter] public object Value { get; set; }
    [Parameter] public EventCallback<object> ValueChanged { get; set; }

   async void OnChange(ChangeEventArgs e)
    {
       await ValueChanged.InvokeAsync(e.Value);
    }
}

现在,我们可以创建名为 DynamicForm 的包装器:

@typeparam T


    @foreach (var p in Properties)
    {
        <DynamicField Value="@p.Value" Caption="@p.Key" ValueChanged="@((e)=>OnValueChanged(e,p.Key))"/>
    }


@code{
    [Parameter] public T Model { get; set; }
    [Parameter] public EventCallback<T> ModelChanged { get; set; }
    public Dictionary<string, object> Properties { get; set; } = new Dictionary<string, object>();

    protected override void OnInitialized()
    {
        var props = Model.GetType().GetProperties();
        foreach (var p in props)
        {
            Properties.Add(p.Name, p.GetValue(Model));
        }
    }

    void OnValueChanged(object e, string prop)
    {
        var p = Model.GetType().GetProperty(prop);
        if (p.PropertyType == typeof(int))
        {
            var intValue = Convert.ToInt32(e);
            p.SetValue(Model, intValue);
        }
        if (p.PropertyType == typeof(string))
        {
            p.SetValue(Model, e.ToString());
        }

        ModelChanged.InvokeAsync(Model);
    }
}

这里实际发生了什么,我们使用反射来获取模型的所有属性,将它们发送到 DynamicFields,当这些值发生更改时,我们将新值设置为模型并调用 ModelChanged 来发送新值。

这在我的计算机上有效,每次我更改值时,MySensorType 都会在 Index 组件上显示新值。

你可以看到我只为Number和String创建了动态字段,如果你有DateTime或Select,你需要扩展这个DynamicField,因为select会比较困难。

顺便说一句,在索引视图上,您​​可以放置​​一个按钮并使用您的逻辑调用 SaveChanges 并使用 MySensorType。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
相关资源
最近更新 更多