web-dev-qa-db-ja.com

動的なフォームを作成する方法

Blazorで動的なフォームを作成しようとしていますが、行き詰まっています。 2つの入力パラメーターを受け取るFormFactoryコンポーネントがあります。データバインディングのモデルと、作成する要素を定義するディクショナリ。アイデアはモデルオブジェクトを渡すことです

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

そして辞書

{ "Name": "string" },
{ "Phone": "string" }

モデルのプロパティにバインドされたNameとPhoneの2つの入力フィールドを持つフォームを作成します。

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

しかし、これは機能しません。私は言ってエラーが出ます

"ブロック内の一部の戻り値の型がデリゲートの戻り値の型に暗黙的に変換できないため、ラムダ式を意図したデリゲート型に変換できません"および "割り当ての左側の側は変数、プロパティ、またはインデクサーである必要があります"

編集: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:指定された式に、サポートされていないMethodCallExpression1が含まれています。 FieldIdentifierは、オブジェクトの単純なメンバーアクセサー(フィールド、プロパティ)のみをサポートします。

どんな助けでもいただければ幸いです

3
partyelite

調査中にこれに遭遇しましたが、結局@bind-valueおよびvalueおよびonchangedを直接使用して、リフレクションを介してプロパティを設定します。

    @foreach (var p in Datacontext.GetType().GetProperties())
    {
        <input type="text" 
               placeholder="@p.Name" 
               value="@p.GetValue(Datacontext)"
               @onchange="(e) => p.SetValue(Datacontext, e.Value)">
    }

このコードは、プロパティのタイプ変換を行わず、onchangeハンドラーでプロパティオブジェクトに対するクロージャーを使用することを示しています。

おそらく誰かがそれを便利だと思うでしょう:)

1
aL3891