假设给定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>
内部局部视图,注意:在一个请求中,外部视图可以多次使用此局部视图,但是如果使用AJAX请求它也可以只使用一次
<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原则。在内部局部视图中进行评估并以这样的方式存储在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>
也许这只是主观问题,但似乎对这种情况会有最好的做法。有什么想法吗?
答案 0 :(得分: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类传递给视图。
答案 1 :(得分:2)
方法3是要走的路 - 但不要让它变得那么复杂。有两个属性 - PurchaseItem
属性和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>