2

モデルの状態が原因で、フォーム ポスト コントローラーで設定されたモデル プロパティがどのようにビューに表示されないかについて、すでにいくつかの良い議論があります。議論をさらに進めるために、モデルの状態が原因で、VIEW 内のアイテムが更新されてもモデルが更新されない例があります。そうです、ユーザーに表示されるものは、投稿で返されるモデル プロパティと一致しません!

リストを持つモデルがあるとします

public class FruitBasket {
    public string OwnersName { get; set; }
    public IEnumerable<Fruit> Fruits { get; set; }
    public string FruitColor { get; set; }
    public FruitBasket() {
        this.OwnersName = "Bob";
        this.FruitColor = "Red";
    }
}
public class Fruit {
    public string Name { get; set; }
    public string Color { get; set; }
}

データ アクセス クラスには、色に基づいて果物のリストを取得するメソッドがあります。

データアクセスコード

public IEnumerable<Fruit> GetFruits(string color) {
    if (color == "Red") {
        List<Fruit> fruits = new List<Fruit> {
            new Fruit { Name = "Apple", Color = "Red" },
            new Fruit { Name = "Grape", Color = "Red" }
        };
        return fruits;
    } else {
        List<Fruit> fruits = new List<Fruit> {
            new Fruit { Name = "Banana", Color = "Yellow"},
            new Fruit { Name = "Apple", Color = "Red" },
            new Fruit { Name = "Grape", Color = "Red" }
        };
        return fruits;
    }
}

コントローラー (db はデータ アクセス クラス)

public ActionResult FruitBasket() {
    FruitBasket basket = new FruitBasket();
    basket.Fruits = db.GetFruits("Red");
    return View(basket);
}
[HttpPost]
public ActionResult FruitBasket(FruitBasket basket) {
    basket.Fruits = db.GetFruits("All");
    return View(basket);
}

意見

@model GEWeb.Models.FruitBasket
<!DOCTYPE html>
<html>
<head>
    <title>FruitBasket</title>
</head>
<body>
@using (Html.BeginForm()) {
    <p>@Html.DisplayFor(model => Model.OwnersName)</p>
    <table>
        @Html.EditorFor(model => model.Fruits)
    </table>
    <input type="submit" value="filter" />
}
</body>
</html>

エディター テンプレート (editorfor のテンプレートは views/shared/EditorTemplates にあります) ポストバック時にモデルにリスト データが入力されるように、hiddenfor ヘルパーが含まれています。

@model GEWeb.Models.Fruit
<tr>
    <td>
        @Html.DisplayFor(model => model.Name)
        @Html.HiddenFor(model => model.Name)
    </td>
    <td>
        @Html.DisplayFor(model => model.Color)
        @Html.HiddenFor(model => model.Color)
    </td>
    <td>
        @Html.CheckBoxFor(model => model.Remove)
    </td>
</tr>

シナリオ - ユーザーがページをリクエストすると、赤い果物のリストが表示されます。- ユーザーがフィルター ボタンをクリックすると、ポスト コントローラーがすべての果物をロードし、ユーザーに 3 つの果物すべてのリストが表示されます。 - ユーザーがもう一度フィルター ボタンをクリックします。ポスト コントローラーに渡されたバスケットのプロパティを調べると、リストはユーザーが見たものと一致しません。

このチェックボックスを使用して、バスケットから削除する果物を選択するとします。果物を削除するデータ アクセス クラスのメソッドに、basket.fruits モデルを渡すことができます。その後、コントローラーに、basket.fruits リストをリロードさせることができます。しかし、コントローラーに返されたリストがユーザーに表示されているものと一致しないため、機能しません。

この「機能」は、以下を Post コントローラーに入れることで覆すことができます。

ModelState.Clear();

しかし、実際には、そうする必要はありません。ビューとコントローラーは、モデルを正確にやり取りする必要があります。ModelState は、ページの読み込み間でビューのプロパティを永続化しようとする試みであり、ビューではなくデータベースによって状態が管理される MVC の哲学と一致していないようです!

4

0 に答える 0