令人感兴趣的是,我的MVC3剃刀格式在foreach
代码块内呈现重复值,尽管从服务器正确接收数据。这是我在MVC3 Razor中的简单形式......
- 我的.cshtml网页示例
@model List<Category>
@using (@Html.BeginForm("Save", "Categories", FormMethod.Post))
{
foreach (Category cat in Model)
{
<span>Test: @cat.CategoryName</span>
<span>Actual: @Html.TextBoxFor(model => cat.CategoryName)</span>
@Html.HiddenFor(model => cat.ID)
<p>---</p>
}
<input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}
我的控制器操作看起来像这样 -
[HttpPost]
public ActionResult Save(ViewModel.CategoryForm cat)
{
... save the data based on posted "cat" values (I correctly receive them here)
List<Category> cL = ... populate category list here
return View(cL);
}
上面的保存操作会返回具有正确数据的模型。
在提交上述表格后,我希望在完成行动后能看到类似于以下类别的价值......
Test: Category1, Actual:Category1
Test: Category2, Actual:Category2
Test: Category3, Actual:Category3
Test: Category4, Actual:Category4
但@Html.TextBoxFor
重复列表中的第一个值。发布表单后,我看到响应如下所示。即使我从服务器获得正确的数据,也会重复“实际”值。
Test: Category1, Actual:Category1
Test: Category2, Actual:Category1
Test: Category3, Actual:Category1
Test: Category4, Actual:Category1
我做错了什么?任何帮助将不胜感激。
答案 0 :(得分:3)
像TextBoxFor
这样的辅助方法旨在与表示单个对象的ViewModel一起使用,而不是对象的集合。
正常使用将是:
@Html.TextBoxFor(c => c.Name)
c
在方法内部映射到ViewData.Model
。
你正在做一些不同的事情:
@Html.TextBoxFor(c => iterationItem.Name)
internall方法仍将尝试使用ViewData.Model作为渲染的基础对象,但您打算在迭代项上使用它。该语法虽然对编译器有效,但可以解决这个问题。
解决方法是创建一个对单个项目进行操作的局部视图:在该视图中,您可以使用具有正确语法的html帮助程序(第一个示例),然后在foreach中调用它,将迭代项目作为参数传递。这应该可以正常工作。
答案 1 :(得分:0)
更好的方法是使用EditorTemplates。
在您的表单中,您可以这样做:
@model List<Category>
@using (@Html.BeginForm("Save", "Categories", FormMethod.Post))
{
@Html.EditorForModel()
<input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}
然后,您将在〜/ Views / Shared文件夹或Controllers View文件夹中创建名为EditorTemplates的文件夹(取决于您是要与整个应用程序共享模板还是仅与此控制器共享),以及在EditorTemplates文件夹中,创建一个如下所示的Category.cshtml文件:
@model Category
<span>Test: @Model.CategoryName</span>
<span>Actual: @Html.TextBoxFor(model => model.CategoryName)</span>
@Html.HiddenFor(model => model.ID)
<p>---</p>
MVC将自动遍历集合并为其中的每个项目调用模板。
答案 2 :(得分:0)
我注意到在Views中使用foreach循环会导致文本框的名称属性对于集合中的每个项目呈现相同。对于您的示例,将使用以下ID和名称属性呈现每个文本框:
<input id="cat_CategoryName" name="cat.CategoryName" value="Category1" type="text">
当您的控制器收到表单数据集合时,它将无法将集合重建为不同的值。
解决方案
我采用的一个好模式是将您的View绑定到要发回的同一个类。在示例中,模型绑定到List<Category>
,但控制器Save方法接收模型ViewModel.CategoryForm
。我会让它们都一样。
使用for
循环代替foreach
。 name / id属性将是唯一的,模型绑定器将能够区分这些值。
我的最终代码:
查看强>
@model CategoryForm
@using TestMvc3.Models
@using (@Html.BeginForm("Save", "Categories", FormMethod.Post))
{
for (int i = 0; i < Model.Categories.Count; i++)
{
<span>Test: @Model.Categories[i].CategoryName</span>
<span>Actual: @Html.TextBoxFor(model => Model.Categories[i].CategoryName)</span>
@Html.HiddenFor(model => Model.Categories[i].ID)
<p>---</p>
}
<input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}
<强>控制器强>
public ActionResult Index()
{
// create the view model with some test data
CategoryForm form = new CategoryForm()
{
Categories = new List<Category>()
};
form.Categories.Add(new Category() { ID = 1, CategoryName = "Category1" });
form.Categories.Add(new Category() { ID = 2, CategoryName = "Category2" });
form.Categories.Add(new Category() { ID = 3, CategoryName = "Category3" });
form.Categories.Add(new Category() { ID = 4, CategoryName = "Category4" });
// pass the CategoryForm view model
return View(form);
}
[HttpPost]
public ActionResult Save(CategoryForm cat)
{
// the view model will now have the correct categories
List<Category> cl = new List<Category>(cat.Categories);
return View("Index", cat);
}