Есть ли способ динамически выполнять двустороннюю привязку в blazor inputtext

#c# #html #asp.net-core #blazor

#c# #HTML #asp.net-core #blazor

Вопрос:

Я пытаюсь создать многоразовый элемент управления. Я выяснил, как обрабатывать сценарии только для чтения, используя отражения с @typeof(TItem).GetProperty(col.PropertyName).GetValue(item)

И теперь я хочу сделать то же самое с двусторонней привязкой, например <InputText @bind-Value="item.{select a property using the PropertyName value in ColumnDefinition}</InputText>"

Есть ли способ выбрать свойство элемента с помощью строки?

Спасибо!

Дополнительные ссылки ниже:

 @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; }
    }
 

Ответ №1:

Вы можете получить значение из свойства любого объекта на основе имени самого свойства.

Пример

 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; }
}
 

Теперь вы можете просто адаптировать это решение к вашему случаю

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

Надеюсь, это сработает, я не так много работаю с файлами razor и не могу протестировать этот случай прямо сейчас, но, по крайней мере, это может привести вас к решению

Комментарии:

1. Привет, спасибо за ответ, но я не думаю, что это сработает. Ваше предложение по сути такое же, как у моего @typeof(TItem). getProperty(col.propertyName). Получить значение (элемент). Чего я хотел бы добиться, так это двусторонней привязки, и, насколько я понимаю, это означает, что мне нужно как получить, так и установить свойство. Я все еще тестировал ваш код, но он не сработал.

Ответ №2:

В Blazor двусторонняя привязка состоит из двух шагов.

  1. В процессе рендеринга значение будет считано и отображено.
  2. Он будет подписываться на событие изменения компонента. Обработчик запишет значение обратно в ваше свойство.

Чтобы позволить компилятору творить чудеса, вы используете @bind-Value вместо Value . Однако вы можете «взломать» систему, самостоятельно установив обработчик событий.

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

В качестве ссылки взгляните на https://docs.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0 .

Ответ №3:

<InputText> отличается от <input>

<InputText> требуется Value , ValueChanged и 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));
    }
}
 

Используя вышеуказанный компонент, вы можете затем сделать

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

Обязательно оберните в <EditForm>