1

html テーブルの部分ビューが与えられ、次のようなテーブル行ごとにネストされた部分ビューが存在するとします。

外側部分図

<table>
<thead>
  <tr>
    <th>Item Name</th>
    <th>Cost</th>
    <th>Category</th>
  </tr>
</thead>
<tbody>
@for (int i = 0; i < Model.PurchaseItems.Count; i++)
{ 
  @Html.Partial("_PurchaseItemsDetail", Model.PurchaseItems[i])
}     
</tbody>
</table>

内部部分ビュー、注: この部分ビューは、1 回の要求で外部ビューによって複数回使用される場合がありますが、AJAX を使用して要求された場合は、1 回だけ使用される場合もあります。

<tr id="@Model.ID">
  <td>@Html.TextBoxFor(x => x.ItemName)</td>
  <td>@Html.TextBoxFor(x => x.Cost)</td>
  <td>
    @Html.DropDownListFor(x => x.Category, CATEGORY_COLLECTION)
  </td>
</tr>

問題: 柔軟であることを意図したこの内部ビューを考えると、データベースにクエリを実行IEnumerable<SelectListItem>し、ドロップダウンで使用するコレクションを一時的に保存する最良の方法は何ですか? 私が考えることができる方法:

方法 1 :これが最も簡単なようですが、 MVC の原則に違反しているように感じます。内部の部分ビューで評価し、データベースが 1 回だけヒットするように ViewData コレクションに格納します。

    @{
     if (ViewData["Categories"] == null)
     {
       ViewData["Categories"] = API.GetCategories();
     }
    }

その後、ビューで

  <td>
    @Html.DropDownListFor(x => x.Category, ViewData["Categories"])
  </td>

これは、含まれているドロップダウンに入力する方法を決定する限り、ビューがそれ自体を処理するため、便利です。ビューモデルに依存しません。

方法 2 : 上記と同じですが、内部の部分ビューを返すさまざまなコントローラー メソッドで ViewData を設定します。この方法は MVC のベスト プラクティスに沿っているように見えますが、各コントローラー メソッドが ViewData を適切に設定し、必要なビュー モデルを作成する必要があることを考えると、維持するのは面倒で混乱を招くようです。

方法 3 :これは最も手間がかかり、保守が最も難しいように見えますが、MVC の原則に最も準拠しています。ViewData 全体を使用することは避けますが、コレクションへの参照を他のプロパティと共に部分ビュー モデルに格納します。コレクションを作成し、各テーブル行のビュー モデルに参照を格納するのはコントローラーの役割です。

public class PurchaseItemModel
{
  public string ItemName { get; set; }
  public decimal Cost { get; set; }
  public string Category { get; set; }

  // add this
  public IEnumberable<SelectListItem> Categories { get; set; }
}

そして、内部ビューを提供する各コントローラーで

// if dealing with multiple rows (GET)
IEnumerable<SelectListItem> collection = API.GetPurchaseItemList();
foreach (PurchaseItemModel pim in OuterModel.PurchaseItemModels)
{
  pim.Categories = collection;
}

また

// if dealing with a single row (Ajax)
purchaseItem.Categories = API.GetPurchaseItemList();

その後、ビューで

  <td>
    @Html.DropDownListFor(x => x.Category, x.Categories)
  </td>

おそらくこれは単なる主観的な質問ですが、この種の状況にはベスト プラクティスがあるようです。何かご意見は?

4

2 に答える 2

2

次のような ViewModel クラスを作成します。

public class PurchaseItemViewModel
{
  public string ItemName { get; set; }
  public decimal Cost { get; set; }
  public string Category { get; set; }
  public IEnumberable<Category> Categories { get; set; }

  public PurchaseItemViewModel(PurchaseItemModel item, List<Category> categories)
  {
       //initialize item and categories
  }
}

コントローラーですべてのアイテムを取得し、すべてのカテゴリを取得してから、購入アイテムを ViewModel に設定し、カテゴリを設定します。したがって、ViewModel クラスをビューに渡します。

于 2013-11-01T22:59:19.837 に答える
2

方法 3 が有効な方法ですが、それほど複雑にしないでください。PurchaseItemプロパティとプロパティの 2 つのプロパティがありCategoriesます。次に、反復ごとにインスタンス化し、プロパティを設定します。

緩い例:

<table>
<thead>
  <tr>
    <th>Item Name</th>
    <th>Cost</th>
    <th>Category</th>
  </tr>
</thead>
<tbody>
@for (int i = 0; i < Model.PurchaseItems.Count; i++)
{ 
    var vm = new PurchaseItemsDetailViewModel()
        {
            PurchaseItem = Model.PurchaseItems[i],
            Categories = Model.CategoriesSelectList // or whatever holds the categories select list
        };
  @Html.Partial("_PurchaseItemsDetail", vm)
}     
</tbody>
</table>


<tr id="@Model.PurchaseItem.ID">
  <td>@Html.TextBoxFor(x => x.PurchaseItem.ItemName)</td>
  <td>@Html.TextBoxFor(x => x.PurchaseItem.Cost)</td>
  <td>
    @Html.DropDownListFor(x => x.PurchaseItem.Category, x.Categories)
  </td>
</tr>
于 2013-11-02T00:37:21.503 に答える