gpt4 book ai didi

Blazor 如何创建动态表单

转载 作者:行者123 更新时间:2023-12-03 15:28:24 31 4
gpt4 key购买 nike

我正在尝试在 Blazor 中创建一个动态表单,但我被卡住了。我有一个带有两个输入参数的 FormFactory 组件。我的数据绑定(bind)模型和定义应创建哪些元素的字典。
这个想法是传递一个模型对象

public class Data 
{
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
}

和一本字典
{ "Name": "string" },
{ "Phone": "string" }

我想创建一个表单,其中包含绑定(bind)到模型中属性的名称和电话的两个输入字段。
<h3>Dynamic form</h3>
<EditForm Model="@DataContext">
@foreach (var field in FieldIdentifiers)
{
if (field.Value == "string")
{
<InputText @bind-Value="DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString()"></InputText>
}
}
</EditForm>
@code {
[Parameter] public object DataContext { get; set; }
[Parameter] public Dictionary<string, string> FieldIdentifiers { get; set; }
}

但这不起作用。我收到一条错误消息

"Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type" and "The left hnad side of an assignment must be a variable, property or indexer"



编辑:
我发现 Blazor 生成导致错误的 ValueChanged 属性
builder2.AddAttribute(8, "ValueChanged", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<Microsoft.AspNetCore.Components.EventCallback<System.String>>(Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(this, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, __value => DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString() = __value, DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString()))));

那行不通,所以我尝试创建一个 RenderFragment 并更改了我的组件,如下所示
<h3>Dynamic form</h3>
@MyForm()


@code {

[Parameter] public object DataContext { get; set; }

[Parameter] public Dictionary<string, string> FieldIdentifiers { get; set; }

RenderFragment MyForm() => builder =>
{
builder.AddMarkupContent(0, "<h3>Dynamic form</h3>\r\n");
builder.OpenComponent<Microsoft.AspNetCore.Components.Forms.EditForm>(1);
builder.AddAttribute(2, "Model", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Object>(DataContext));
builder.AddAttribute(3, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.Forms.EditContext>)((context) => builder2 =>
{
builder2.AddMarkupContent(4, "\r\n");
foreach (var field in FieldIdentifiers)
{
if (field.Value == "string")
{
builder2.AddContent(5, " ");
builder2.OpenComponent<Microsoft.AspNetCore.Components.Forms.InputText>(6);
builder2.AddAttribute(7, "Value", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.String>(Microsoft.AspNetCore.Components.BindMethods.GetValue(DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString())));
builder2.AddAttribute(8, "ValueChanged", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<Microsoft.AspNetCore.Components.EventCallback<System.String>>(Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(this, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, __value => DataContext.GetType().GetProperty(field.Key).SetValue(DataContext, __value), DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString()))));
builder2.AddAttribute(9, "ValueExpression", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Linq.Expressions.Expression<System.Func<System.String>>>(() => Convert.ToString(DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null))));
builder2.CloseComponent();
builder2.AddMarkupContent(10, "\r\n");
}
}

builder2.AddMarkupContent(11, "\r\n");
}));
builder.CloseComponent();
};
}

这可以编译,但我得到一个运行时错误

System.ArgumentException: The provided expression contains a MethodCallExpression1 which is not supported. FieldIdentifier only supports > simple member accessors (fields, properties) of an object.



任何帮助,将不胜感激

最佳答案

有关工作示例,请参见 BlazorFiddle

您的问题出在 ValueExpression 上,它要求它是一个表达式才能获取属性(或类似属性)。
我在我的示例中创建了这个:

var constant = System.Linq.Expressions.Expression.Constant(DataContext, typeof(DataX));
var exp = System.Linq.Expressions.MemberExpression.Property(constant, fld);
var lamb = System.Linq.Expressions.Expression.Lambda<Func<string>>(exp);
builder.AddAttribute(4, "ValueExpression", lamb);

对于 ValueValueChanged 我使用反射来获取和设置属性值。
// Get the initial property value
var propInfoValue = typeof(DataX).GetProperty(fld);
var s = propInfoValue.GetValue(DataContext);
builder.AddAttribute(1, "Value", s);

// Create the handler for ValueChanged. I use reflection to the value.
builder.AddAttribute(3, "ValueChanged", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<Microsoft.AspNetCore.Components.EventCallback<System.String>>(Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(this, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, __value => propInfoValue.SetValue(DataContext, __value), (string)propInfoValue.GetValue(DataContext)))));

我对 Linq 的 Expression 类很陌生,所以可能有更好的方法来做到这一点。 ValueChanged 的代码也是基于为静态 InputText 生成的代码。也可能有更好的方法。

完整代码:
索引.razor
@page "/"

<h3>Dynamic form</h3>
<EditForm Model="@DataContext">
@foreach (var field in FieldIdentifiers)
{
if (field.Value == "string")
{
@field.Key
@CreateComponent(field.Key);
<br />
}
}

<h3>Statically declared</h3>
<InputText @bind-Value="@DataContext.Name"></InputText> <br>
Name: @DataContext.Name
</EditForm>

@code {
[Parameter] public DataX DataContext { get; set; } = new DataX();
[Parameter] public Dictionary<string, string> FieldIdentifiers { get; set; } = new Dictionary<string, string> { { "Name", "string" }, { "Phone", "string" } };

public RenderFragment CreateComponent(string fld) => builder =>
{
builder.OpenComponent(0, typeof(InputText));

// Get the initial property value
var propInfoValue = typeof(DataX).GetProperty(fld);
var s = propInfoValue.GetValue(DataContext);
builder.AddAttribute(1, "Value", s);

// Create the handler for ValueChanged. I use reflection to the value.
builder.AddAttribute(3, "ValueChanged", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<Microsoft.AspNetCore.Components.EventCallback<System.String>>(Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(this, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, __value => propInfoValue.SetValue(DataContext, __value), (string)propInfoValue.GetValue(DataContext)))));

// Create an expression to set the ValueExpression-attribute.
var constant = System.Linq.Expressions.Expression.Constant(DataContext, typeof(DataX));
var exp = System.Linq.Expressions.MemberExpression.Property(constant, fld);
var lamb = System.Linq.Expressions.Expression.Lambda<Func<string>>(exp);
builder.AddAttribute(4, "ValueExpression", lamb);

builder.CloseComponent();
};
}

DataX.cs
public class DataX
{
public string Name { get; set; } = "Jane Doe";
public string Phone { get; set; } = "123456789";
public string Address { get; set; } = "The Street";
}

编辑 :我刚刚看到您在问题上有“blazor-clientside”标签。我刚刚使用服务器端 Blazor 对此进行了测试。

关于Blazor 如何创建动态表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57426177/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com