C#MVC发送和检索列表<>使用一个模型进出视图

时间:2016-06-01 15:30:30

标签: c# asp.net-mvc views controllers

我正在尝试编写一个检索List<>的页面。从SQL表中显示它,以便用户可以进行更改。我已经能够显示信息了。我遇到了提交问题。我无法找到一种方法来获取输入的数据并将更改发送到List<>所以我可以在控制器/模型中操纵它。

目前我在提交时将新数据放入数组中。因为我在视图中使用@model List<modelname>。是否可以替换值或可能将数据放入View中的新列表?

1 个答案:

答案 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操作中放置断点并单击“提交”按钮,则会注意到employeesnull。原因是因为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" />

这允许默认模型绑定器将IdName与每个EmployeeViewModel相关联,从而允许它在服务器上正确构造类型。

此时,问题已解决,但是,如果可以避免,则不建议使用for循环,这会将我们带到编辑器模板。编辑器模板是HtmlHelper方法,允许我们为给定类型呈现自定义模板(即视图)。因此,让我向您展示如何使用上面的示例代码执行此操作的示例。

首先,您需要执行以下操作:

  1. EditorTemplates文件夹中创建~/Views/Home/文件夹(EditorTemplates名称在MVC中具有特殊含义,因此正确拼写是很重要的。)
  2. 在该文件夹中创建一个EmployeeViewModel.cshtml视图(同样,这里的名称很重要:它应该与您希望为其创建自定义模板的类型相匹配)。
  3. 完成后,它应如下所示:

    Editor templates example

    现在,打开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.EditorForHtml.DisplayFor都非常聪明,可以识别他们何时被调用集合,因此他们会寻找自定义模板来呈现集合的类型(在本例中为{ {1}}将查找EditorFor)的编辑器模板。

    由于我们提供了一个编辑器模板,它不仅会为集合中的每个项目渲染它,还会为每个项目生成正确的索引,为模型绑定器提供重建所需的所有信息。在服务器上收集。

    最终结果是模型绑定变得更简单,不仅是您的视图的代码更简单,它还根据所涉及的类型进行拆分,这使您的视图更容易使用,而不是拥有巨型视图可以做任何事情。

    我还应该提一下,因为我的示例是直接使用集合,而不是更多,您实际上可以用EmployeeViewModel替换@Html.EditorFor(x => x)。我最初并没有这样做,因为我不想给人的印象是只使用后者来调用模板。