Я пытаюсь создать многоразовый элемент управления.
Я понял, как обрабатывать сценарии только для чтения, используя отражения с помощью @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; }
}
🤔 А знаете ли вы, что...
C# позволяет создавать собственные библиотеки классов и использовать их в других проектах.
Вы можете получить значение свойства любого объекта на основе имени самого свойства.
Пример
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>
Надеюсь, это сработает, я не так много работаю с файлами бритвы и не могу проверить этот случай прямо сейчас, но, по крайней мере, это может привести вас к решению.
В Blazor двусторонняя привязка состоит из двух шагов.
Чтобы позволить компилятору творить чудеса, вы используете @bind-Value
вместо Value
. Однако вы можете «взломать» систему, установив обработчик событий самостоятельно.
<InputText
Value = "@typeof(TItem).GetProperty(col.PropertyName).GetValue(item)"
ValueChanged = "@(e => typeof(TItem).GetProperty(col.PropertyName).SetValue(item,e))">
</InputText>
В качестве справки взгляните на https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0.
<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>