我正在尝试编写一个检索List<>的页面。从SQL表中显示它,以便用户可以进行更改。我已经能够显示信息了。我遇到了提交问题。我无法找到一种方法来获取输入的数据并将更改发送到List<>所以我可以在控制器/模型中操纵它。
目前我在提交时将新数据放入数组中。因为我在视图中使用@model List<modelname>
。是否可以替换值或可能将数据放入View中的新列表?
答案 0 :(得分:0)
你绝对可以这样做,但人们最初往往会遇到问题,所以我会提供一个完整的例子。
首先,让我们定义一个HomeController
,其Index
动作返回List<EmployeeViewModel>
:
public class HomeController : Controller
{
public ActionResult Index()
{
// Assume this would really come from your database.
var employees = new List<EmployeeViewModel>()
{
new EmployeeViewModel { Id = 1, Name = "Employee 1" },
new EmployeeViewModel { Id = 2, Name = "Employee 2" },
new EmployeeViewModel { Id = 3, Name = "Employee 3" },
};
return View(employees);
}
[HttpPost]
public ActionResult Index(List<EmployeeViewModel> employees)
{
// Rest of action
}
}
人们首先解决此问题的典型方法是在index.cshtml
中执行以下操作:
@model List<EmployeeViewModel>
@using (Html.BeginForm())
{
foreach (var item in Model)
{
<div class="row">
@Html.EditorFor(x => item.Id)
</div>
<div class="row">
@Html.EditorFor(x => item.Name)
</div>
}
<input type="submit" />
}
乍一看,这看起来会起作用。但是,如果在POST操作中放置断点并单击“提交”按钮,则会注意到employees
为null
。原因是因为foreach
循环正在生成HTML,如下所示:
<input name="item.Id" type="number" value="1" />
<input name="item.Name" type="text" value="Employee 1" />
<input name="item.Id" type="number" value="2" />
<input name="item.Name" type="text" value="Employee 2" />
<input name="item.Id" type="number" value="3" />
<input name="item.Name" type="text" value="Employee 3" />
我在那里删除了一些不相关的部分,但请注意name
属性如何为每个员工提供相同的值。当默认模型绑定器尝试在服务器上构建数据列表时,它必须能够区分不同的员工,并且由于它不能,因此导致列表为null
。
那为什么它会生成相同的值?这是因为:
@Html.EditorFor(x => item.Id)
@Html.EditorFor(x => item.Name)
我们没有将索引值传递给HtmlHelper
方法调用,因此该信息不会传递给生成的HTML。我们可以通过使用for
循环来解决这个问题:
for (int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(x => Model[i].Id)
@Html.EditorFor(x => Model[i].Name)
}
由于我们现在为每个方法调用提供索引,因此生成的HTML现在包含每个员工的索引:
<input name="[0].Id" type="number" value="1" />
<input name="[0].Name" type="text" value="Employee 1" />
<input name="[1].Id" type="number" value="2" />
<input name="[1].Name" type="text" value="Employee 2" />
<input name="[2].Id" type="number" value="3" />
<input name="[2].Name" type="text" value="Employee 3" />
这允许默认模型绑定器将Id
和Name
与每个EmployeeViewModel
相关联,从而允许它在服务器上正确构造类型。
此时,问题已解决,但是,如果可以避免,则不建议使用for
循环,这会将我们带到编辑器模板。编辑器模板是HtmlHelper
方法,允许我们为给定类型呈现自定义模板(即视图)。因此,让我向您展示如何使用上面的示例代码执行此操作的示例。
首先,您需要执行以下操作:
EditorTemplates
文件夹中创建~/Views/Home/
文件夹(EditorTemplates
名称在MVC中具有特殊含义,因此正确拼写是很重要的。)EmployeeViewModel.cshtml
视图(同样,这里的名称很重要:它应该与您希望为其创建自定义模板的类型相匹配)。完成后,它应如下所示:
现在,打开EmployeeViewModel.cshtml
,并将Index.cs
内的渲染代码放在其中:
@model EmployeeViewModel
<div class="row">
@Html.EditorFor(x => x.Id)
</div>
<div class="row">
@Html.EditorFor(x => x.Name)
</div>
最后,打开index.cshtml
并将其更改为以下内容:
@model List<EmployeeViewModel>
@using (Html.BeginForm())
{
@Html.EditorFor(x => x)
<input type="submit" />
}
Html.EditorFor
和Html.DisplayFor
都非常聪明,可以识别他们何时被调用集合,因此他们会寻找自定义模板来呈现集合的类型(在本例中为{ {1}}将查找EditorFor
)的编辑器模板。
由于我们提供了一个编辑器模板,它不仅会为集合中的每个项目渲染它,还会为每个项目生成正确的索引,为模型绑定器提供重建所需的所有信息。在服务器上收集。
最终结果是模型绑定变得更简单,不仅是您的视图的代码更简单,它还根据所涉及的类型进行拆分,这使您的视图更容易使用,而不是拥有巨型视图可以做任何事情。
我还应该提一下,因为我的示例是直接使用集合,而不是更多,您实际上可以用EmployeeViewModel
替换@Html.EditorFor(x => x)
。我最初并没有这样做,因为我不想给人的印象是只使用后者来调用模板。