4

我正在开发一个允许用户添加一个或多个其他用户的管理面板。有一个文本区域,管理员可以在其中输入一个或多个要添加到应用程序的用户 ID,这对应于在就业过程中分配的用户 ID。提交时,应用程序从包含所有员工的数据库中提取姓名、电子邮件等,并将其显示在屏幕上以供验证。屏幕上还包括一些用于分配某些权限的复选框,例如CanWriteIsAdmin

看法

using (Html.BeginForm())
        {
            <table>
                <tr>
                    <th>
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.User.First().ID)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.User.First().Name)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.User.First().Email)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.User.First().CanWrite)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.User.First().IsAdmin)
                    </th>
                </tr>

                @foreach (var item in Model.User)
                {
                    <tr>
                        <td>
                            <input type="checkbox" name="id" value="@item.ID" checked=checked/>
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.ID)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Name)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Email)
                        </td>
                        <td>
                            @Html.CheckBoxFor(modelItem => item.CanWrite)
                        </td>
                        <td>
                            @Html.CheckBoxFor(modelItem => item.IsAdmin)
                        </td>
                    </tr>
                }

            </table>
            <input type="submit" />
        }

注意:带有名称的复选框的原因ID是允许在获取名称和其他信息后不添加用户,例如,您无意添加的用户意外进入了 ID 列表。

模型

public class User
{
    public int ID { set; get; }
    public string Name { set; get; }
    public bool IsAdmin { set; get; }
    public bool CanWrite { set; get; }
    public string Email{ set; get; }

}

控制器

[HttpPost]
public ActionResult Create(IEnumerable<User> model)
{
    //With this code, model shows up as null
}

对于单个用户,我知道我可以将User model其用作控制器操作中的参数。如何调整此代码以同时添加多个用户?这甚至可能吗?

4

3 回答 3

1

我才刚开始使用 ASP.NET MVC,但我想您只需要创建一个视图模型类,该类具有IEnumerable<User>存储用户集合的类型属性。然后将其传递给您的视图并返回给您的POST处理程序。

于 2013-09-25T17:21:17.897 回答
1

你在正确的轨道上,杰夫。你只需要扩展你所拥有的东西。

首先,您的模型null在您的操作中的原因是因为输入字段在您的表单上的命名方式。您的字段将按照以下方式呈现:

<input id="item_CanWrite" name="item.CanWrite" type="checkbox" value="true" />
<input name="item.CanWrite" type="hidden" value="false" />

注意nameitem.CanWrite。这里的问题是,因为您要遍历模型中的所有用户,所以您实际上为所有输入字段提供了相同的名称。这会阻止 MVC 能够对 POST 数据进行模型绑定,因为它无法区分每个User.

为了解决这个问题,您需要将调用更改Html.DisplayFor为以允许 MVC 将每个User作为单独的实体处理,从而允许每个User的字段集按顺序命名。这允许模型绑定器正确绑定到这些字段。像这样:

@for (int i = 0; i < Model.Count(); i++)
{
    <tr>
        <td>
            <input type="checkbox" name="id" value="@Model[i].ID" checked=checked/>
        </td>
        <td>
            @Html.DisplayFor(m => m[i].ID)
        </td>
        <td>
            @Html.DisplayFor(m => m[i].Name)
        </td>
        <td>
            @Html.DisplayFor(m => m[i].Email)
        </td>
        <td>
            @Html.CheckBoxFor(m => m[i].CanWrite)
        </td>
        <td>
            @Html.CheckBoxFor(m => m[i].IsAdmin)
        </td>
    </tr>
}

如果您现在检查这些字段是如何呈现为 HTML 的,您会看到它们看起来像这样:

<input checked="checked" data-val="true" data-val-required="The CanWrite field is required." name="[0].CanWrite" type="checkbox" value="true" />
<input name="[0].CanWrite" type="hidden" value="false" />
<input checked="checked" data-val="true" data-val-required="The CanWrite field is required." name="[1].CanWrite" type="checkbox" value="true" />
<input name="[1].CanWrite" type="hidden" value="false" />

如您所见,每个User都有自己独立的索引。我使用了一个简单的测试设置和以下控制器方法,它在我的测试模型中获取了正确数量的记录:

[HttpPost]
public ActionResult Index(IEnumerable<User> model)
{
    // Process your data.

    return View(model);
}

但是,我想在这里提出一项进一步的改进,以消除您认为的逻辑。为此,我们可以使用DisplayTemplates而不是循环:

  1. DisplayTemplates在视图的当前文件夹内创建一个文件夹(例如,如果您的视图是Home\Index.cshtml,则创建文件夹Home\DisplayTemplates)。
  2. 在该目录中创建一个名称与您的模型匹配的强类型视图(即,在这种情况下,该视图将被称为User.cshtml)。
  3. 将重复的逻辑放在视图中。

你的模板现在应该看起来像这样(禁止你的User模型所在的命名空间):

@model User

<tr>
    <td>
        <input type="checkbox" name="id" value="@Model.ID" checked=checked/>
    </td>
    <td>
        @Html.DisplayFor(m => m.ID)
    </td>
    <td>
        @Html.DisplayFor(m => m.Name)
    </td>
    <td>
        @Html.DisplayFor(m => m.Email)
    </td>
    <td>
        @Html.CheckBoxFor(m => m.CanWrite)
    </td>
    <td>
        @Html.CheckBoxFor(m => m.IsAdmin)
    </td>
</tr>

现在,在您的原始视图中,您可以将所有循环替换为:

@using (Html.BeginForm())
{
    <table>
        @Html.DisplayForModel()
    </table>
    <input type="submit" value="Submit" />
}

如果您想了解有关绑定到集合的更多信息,请参阅我为另一个问题提供的答案。

于 2013-09-25T18:29:53.293 回答
1

尝试这样的事情:

模型

public class Employee
{
    public IEnumerable<User> Employees { set; get; }
}

public class User
{
    public int ID { set; get; }
    public string Name { set; get; }
    public bool IsAdmin { set; get; }
    public bool CanWrite { set; get; }
    public string Email{ set; get; }
}

看法

@model Employee

@using( Html.BeginForm()
{
    // build HTML table, not much different from yours
}

控制器

[HttpPost]
public ActionResult Create(Employee model)
{
    // model will have an IEnumerable property with the User info
}
于 2013-09-25T17:36:37.720 回答