18

これが以前に尋ねられた場合はお詫び申し上げます。それを表現する方法は無数にあるため、答えを探すのは難しいことがわかっています。

次のプロパティを持つビューモデルがあります。

public class AssignSoftwareLicenseViewModel
{
    public int LicenseId { get; set; }
    public ICollection<SelectableDeviceViewModel> Devices { get; set; }
}

SelectableDeviceViewModel の簡略化されたバージョンは次のようになります。

public class SelectableDeviceViewModel
{
    public int DeviceInstanceId { get; set; }
    public bool IsSelected { get; set; }
    public string Name { get; set; }
}

私のビューでは、入力フォーム内に Devices プロパティの編集可能なチェックボックスのリストを表示しようとしています。現在、私のビューは次のようになっています。

@using (Html.BeginForm())
{
    @Html.HiddenFor(x => Model.LicenseId)
    <table>
        <tr>
            <th>Name</th>
            <th></th>
        </tr>
        @foreach (SelectableDeviceViewModel device in Model.Devices)
        {
            @Html.HiddenFor(x => device.DeviceInstanceId)
            <tr>
                <td>@Html.CheckBoxFor(x => device.IsSelected)</td>
                <td>@device.Name</td>
            </tr>
        }
    </table>

    <input type="submit" value="Assign" />
}

問題は、モデルがコントローラーに戻されると、Devices が null になることです。

コンテンツを編集しているにもかかわらず、Devices プロパティがフォームに明示的に含まれていないため、これが発生していると思います。HiddenFor でそれを含めようとしましたが、その結果、モデルのリストが null ではなく空のリストになりました。

ここで何が間違っているのか分かりますか?

4

2 に答える 2

30

コンテンツを編集しているにもかかわらず、Devices プロパティがフォームに明示的に含まれていないため、これが発生していると思います。

いいえ、あなたの仮定は間違っています。これが適切にバインドされない理由は、入力フィールドの名前が正しくないためです。たとえば、それらはname="IsSelected"の代わりに呼び出されname="Devices[0].IsSelected"ます。コレクションへのバインドに使用する必要がある正しいワイヤー形式を見てみましょう: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

しかし、なぜこれが起こるのですか?

ビューで使用したループが原因で発生foreachします。チェックボックスのラムダ式として使用x => device.IsSelectedしましたが、これは Devices プロパティをまったく考慮していません (Web ページの生成されたソース コードを見るとわかります)。

それで、私は何をすべきですか?

個人的には、複雑なプロパティのナビゲーション コンテキストを尊重し、正しい入力名を生成するエディター テンプレートを使用することをお勧めします。したがって、ビュー内のループ全体を取り除きforeach、1 行のコードに置き換えます。

@Html.EditorFor(x => x.Devices)

次に、Devices コレクションの各要素に対して ASP.NET MVC によって自動的にレンダリングされるカスタム エディター テンプレートを定義します。警告: このテンプレートの場所と名前は、規則に従って機能するため非常に重要です: ~/Views/Shared/EditorTemplates/SelectableDeviceViewModel.cshtml:

@model SelectableDeviceViewModel
@Html.HiddenFor(x => x.DeviceInstanceId)
<tr>
    <td>@Html.CheckBoxFor(x => x.IsSelected)</td>
    <td>@Html.DisplayFor(x => x.Name)</td>
</tr>

もう 1 つの方法 (お勧めしません) はICollection、ビュー モデルの current をインデックス付きコレクション ( anIList<T>または arrayなどT[]) に変更することです。

public class AssignSoftwareLicenseViewModel
{
    public int LicenseId { get; set; }
    public IList<SelectableDeviceViewModel> Devices { get; set; }
}

そして、foreach の代わりにforループを使用します。

@for (var i = 0; i < Model.Devices.Count; i++)
{
    @Html.HiddenFor(x => x.Devices[i].DeviceInstanceId)
    <tr>
        <td>@Html.CheckBoxFor(x => x.Devices[i].IsSelected)</td>
        <td>@Html.DisplayFor(x => x.Devices[i].Name</td>
    </tr>
}
于 2012-07-27T06:23:45.327 に答える
0

EditorFor テンプレートは機能し、コードをクリーンに保ちます。ループは必要なく、モデルは正しくポストバックされます。

ただし、複雑なビューモデル (ネストされた EditorFor テンプレート) の検証で問題が発生した人はいますか? Kendo Validator を使用していますが、あらゆる種類の jquery エラーが発生しています。

于 2013-01-09T06:42:26.473 に答える