Reputation: 685
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; }
}
Upvotes: 1
Views: 3887
Reputation: 685
<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>
Upvotes: 2
Reputation: 2601
In Blazor, a two-way binding consists of two steps.
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://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-5.0.
Upvotes: 1
Reputation: 1030
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
Upvotes: 1