0

これは大当たりになりそうですね…。

わかりましたので、同じページで親レコードを編集し、子レコードを追加/削除/編集できるという適度に頻繁なテーマを持つMVC4 Webサイトを構築しています。MVC の魔法を使用して、次のように子レコードの部分ビューを定義できます。

@model NFBC.Models.SubMap

<tr id="@String.Concat("SubMap", ViewBag.Index)">
    <td class="mapname">
        <input type="hidden" name="submaps[@ViewBag.Index].Id" value="@Model.Id" />
        <input type="text" name="submaps[@ViewBag.Index].MapName" value="@Model.MapName" />
    </td>
    <td class="miles"><input type="text" name="submaps[@ViewBag.Index].Miles" value="@Model.Miles" /></td>
    <td class="difficulty">@Html.DropDownList("submaps[" + (string)ViewBag.Index.ToString() + "].DifficultyId", (SelectList)ViewBag.Difficulty(Model.DifficultyId))</td>
    <td class="elevation"><input type="text" name="submaps[@ViewBag.Index].Elevation" value="@Model.Elevation" /></td>
    <td class="mapfile"><input type="text" name="submaps[@ViewBag.Index].MapFile" value="@Model.MapFile" /></td>
    <td class="delete"><img src="~/Images/Error_red_16x16.png" /></td>
</tr>

次に、親ビューで部分ビューを呼び出して、そのすべての子をレンダリングします。

<table id="ChoicesTable">
    <thead>
        <tr>
            <th>Map Name</th>
            <th>Miles</th>
            <th>Difficulty</th>
            <th>Elevation</th>
            <th>Map File</th>
            <th></th>
        </tr>
    </thead>
    for (int i = 0; i < Model.SubMaps.Count; i++)
    {
        var map = Model.SubMaps.ElementAt(i);
        ViewBag.Index = i;
        Html.RenderPartial("_MapChoiceEditRow", map);
    }
</table>

「サブ エンティティ」の名前の構文 (つまり、name="subMaps[@ViewBag.Index].Id") に関するドキュメントを見つけることができませんが、モデルにバインドするときに機能します。インデックス値が 0 から始まり、値が欠落していない限り、すべての子が埋められます (つまり、0、1、2、4、5 は 0、1、および 2 のみをバインドします)。jQuery の Ajax 呼び出しの魔法を使用して、クライアント側で行を動的に挿入および削除できます。

問題は、子エンティティ コントロールで @Html.EditorFor() を確実に使用する方法を単純に理解できないことです。EditorFor は控えめな jquery 検証属性のすべてを html に挿入するため、これは非常に優れた機能です。現在、私は基本的に、独自の「data-val = 'true'」タグ(例には示されていません。まだ行っていません)を追加して、この動作をエミュレートすることを余儀なくされていますが、これは非常に面倒です。 .

そこで、組み込みのテンプレートを使用して、独自のテンプレートを作成してこのようなものを挿入するという素晴らしいアイデアを思いつきました (「ヘルパー」テキストの Bootstraps の「プレースホルダー」属性やツールチップなど、他の独自のものも同様です)。等)。MVC ソースをダウンロードし、デフォルトのエディター テンプレートを開きましたが、目立たない値をレンダリングするマークアップが表示される代わりに、ある時点で目立たない属性を「魔法のように」レンダリングするヘルパー関数を大量に取得するだけです。検証はすべて、アクセスできない内部クラスにパックされているため、それがどのように行われるかわかりません。

ここで何かが欠けているのでしょうか、それとも回避しなければならない MVC の弱点にすぎないのでしょうか。目立たない検証属性生成コードを自分でエミュレートする必要がないようにしたいのですが、それが唯一の解決策である場合は、それができると思います...

ありがとう!

4

1 に答える 1

2

午後はソース コードをいじって、必要なことを実行できるいくつかの重要なヘルパー メソッドを発見しました。

それは世界で最も美しいものではありませんが、私が以前行っていたことを自動化するのに大いに役立ちます. 私の解決策は、TextBoxForChild と呼ばれる新しい TextBoxFor ヘルパー メソッドを作成することでした。

    public static MvcHtmlString TextBoxForChild<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            string parentName,
            int index,
            IDictionary<string, object> htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var rules = ModelValidatorProviders.Providers.GetValidators(metadata, htmlHelper.ViewContext).SelectMany(v => v.GetClientValidationRules());

        if (htmlAttributes == null)
            htmlAttributes = new Dictionary<String, object>();
        if (!String.IsNullOrWhiteSpace(metadata.Watermark))
            htmlAttributes["placeholder"] = metadata.Watermark;
        UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(rules, htmlAttributes);

        return htmlHelper.TextBox(String.Format("{0}[{1}].{2}", parentName, index, metadata.PropertyName), metadata.Model, htmlAttributes);
    }

「ModelMetadata」オブジェクトを取得し、モデルの「モデル バリデータ ルール」を生成します。次に、カスタムの「プレースホルダー」html 属性に透かしメタデータ値を入力し、最後に「UnobtrusiveValidationAttributesGenerator.GetValidationAttributes」を呼び出します。これにより、html 属性辞書にすべての検証属性が入力されます。

次に、入力名が MVC 子エンティティの形式に従っていることを確認するために、カスタム文字列の書式設定を行います。

参考までに、その「ウォーターマーク」の値がどこから来たのか疑問に思っている人がいる場合、それは「Prompt」と呼ばれる「DisplayAttribute」の値です。

public class FamilyMember
{
    public int ClubNumber { get; set; }

    [Display(Name="Name", Prompt="Name")]
    [Required]
    public string Name { get; set; }
    public string Cell { get; set; }
    public string Email1 { get; set; }
    public string Email2 { get; set; }
    public DateTime? BirthDate { get; set; }
}

素晴らしい!

于 2012-12-28T22:11:07.130 に答える