简体   繁体   中英

Is there a way to do two-way binding in blazor inputtext dynamically

I am trying to create a reusable control. I have figured out how to handle the read-only scenarios using reflections with @typeof(TItem).GetProperty(col.PropertyName).GetValue(item)

And now I want to do the same with two-way binding Like <InputText @bind-Value="item.{select a property using the PropertyName value in ColumnDefinition}</InputText>"

Is there a way to select the item's property using a string?

Thanks!

More references below:

@typeparam TItem
<EditForm>
    <table>
        <thead>
            <tr>
                <Virtualize Items="ColumnDefinitions" Context="col">
                    <th>
                        @col.Caption
                    </th>
                </Virtualize>
            </tr>
        </thead>
        <tbody>
            <Virtualize Items="Items" Context="item">
                <tr>
                    <Virtualize Items="ColumnDefinitions" Context="col">
                        <td>
                            @typeof(TItem).GetProperty(col.PropertyName).GetValue(item)
                            <InputText @bind-Value=""></InputText>
                        </td>
                    </Virtualize>
                </tr>
            </Virtualize>
        </tbody>
    </table>
</EditForm>


@code {
    [Parameter] public List<ColumnDefinition> ColumnDefinitions { get; set; }
    [Parameter] public List<TItem> Items { get; set; }
}

    public class ColumnDefinition
    {
        public short Order { get; set; }
        public string Caption { get; set; }
        public bool IsReadOnly { get; set; } = true;
        public InputTypeEnum InputType { get; set; } = InputTypeEnum.Text;
        public string PropertyName { get; set; }
    }

You can get a value from a property on any object based on the name of the property itself.

Example

public class Program
{
    public static void Main()
    {
        var tst = new MyClass { MyProperty = 1 };           
        var propValue = tst.GetType().GetProperties().FirstOrDefault(p => p.Name == "MyProperty").GetValue(tst);
        Console.WriteLine(propValue);           
    }           
}

public class MyClass {
    public int MyProperty { get;set; }
}

Now you can just adapt this solution to your case

<Virtualize Items="ColumnDefinitions" Context="col">
    <td>                            
        <InputText @bind-Value="@typeof(TItem).GetProperties().FirstOrDefault(p => p.Name == col.PropertyName).GetValue(item);"></InputText>
    </td>
</Virtualize>

Hope this works, i dont work as much with razor files and cannot test this case right now, but at leats it can lead you to a solution

In Blazor, a two-way binding consists of two steps.

  1. In the render process, the value will be read and displayed.
  2. It will subscribe to the change event of the component. The handler will write the value back to your property.

To let the compiler do the magic, you use @bind-Value instead of Value . However, you could "hack" the system by setting the event handler by yourself.

<InputText 
   Value="@typeof(TItem).GetProperty(col.PropertyName).GetValue(item)" 
   ValueChanged="@(e => typeof(TItem).GetProperty(col.PropertyName).SetValue(item,e))">
</InputText>

As a reference, have a look at https://docs.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0 .

<InputText> is different from <input>

<InputText> requires Value , ValueChanged and ValueExpression .

@typeparam TItem
@using System.Linq.Expressions

<InputText Value="@Value"
           ValueChanged="@ValueChanged"
           ValueExpression="@ValueExpression"
           class="form-control">
</InputText>

@code {
    [Parameter] public TItem Item { get; set; }
    [Parameter] public string PropertyName { get; set; }
    private string Value;
    private EventCallback<string> ValueChanged;
    private Expression<Func<string>> ValueExpression;

    protected override void OnInitialized()
    {
        Value = typeof(TItem).GetProperty(PropertyName).GetValue(Item).ToString();
        ValueChanged = Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(Item, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(Item, _value => typeof(TItem).GetProperty(PropertyName).SetValue(Item, _value), (string)typeof(TItem).GetProperty(PropertyName).GetValue(Item)));
        ValueExpression = Expression.Lambda<Func<string>>(Expression.Property(Expression.Constant(Item, typeof(TItem)), PropertyName));
    }
}

Using the above component you can then do

<CustomInputText TItem="TItem" Item="item" PropertyName="@col.PropertyName">

Make sure to wrap in in <EditForm>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM