将未知数量的输入元素绑定到MVC5中的模型

本文关键字:MVC5 模型 绑定 元素 未知数 输入 | 更新日期: 2023-09-27 18:28:15

我对MVC5和C#还很陌生,我正在努力实现一些我不完全理解的东西。

我有一个这样的团队模型:

public class Team
{
    [Key]
    public Guid ID { get; set; }
    public string TeamName { get; set; }
    public string Coach { get; set; }
    public string Conference { get; set; }
}

我也有一个这样的播放器模型:

public class Player
{
    [Key]
    public Guid Id { get; set; }
    [ForeignKey("Teams")]
    public Guid TeamId { get; set; }
    public string Name { get; set; }
    public virtual Team Teams { get; set; }
}

视图模型为

public class TeamViewModel
{
    public string TeamName { get; set; }
    public string Coach { get; set; }
    public string Conference { get; set; }
    public List<Player> Players { get; set; }
}

有了这种结构,你就可以为每支球队增加无限数量的球员。因此,我有一个几乎没有属性的Teams表和一个包含球员姓名和球员TeamId的Player表,这样我们就可以知道他们属于哪个球队。

我的问题出现在我组建团队的时候。我有创建这样的控制器:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(TeamViewModel model)
{
    if (ModelState.IsValid)
    {
        var team = new Team { TeamName = model.TeamName, Coach = model.Coach, Conference = model.Conference, Player = model.Player };
        db.Teams.Add(team);
        var result = await db.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View();
}

我的观点如下:

@model SoccerTeams.Models.ViewModels.TeamViewModel
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <h4>Team</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.TeamName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.TeamName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.TeamName, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Coach, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Coach, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Coach, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Conference, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Conference, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Conference, "", new { @class = "text-danger" })
            </div>
        </div>
        @if (@Model != null)
        {
            foreach (var p in Model.Player)
            {
                <div class="form-group">
                    @Html.Raw("<label class='"control-label col-md-2'">" + p.ToString() + "</label>")
                    <div class="col-md-10">
                        @Html.Raw("<input class='"form-control text-box single-line'" name='"Player'" type-'"text'"")
                    </div>
                </div>
            }
        }
        else
        {
            <div class="form-group">
                @Html.Raw("<label class='"control-label col-md-2'">Player</label>")
                <div class="col-md-10">
                    @Html.Raw("<input class='"form-control text-box single-line'" name='"Player'" type-'"text'"")
                </div>
            </div>
        }
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

据我所知,View应该能够将输入元素转换为列表,并将其传递给我的ViewModel。但是,我的ViewModel总是显示为null。

我错过了什么?我该如何做到这一点?

附言:我知道我可以使用Html.EditorFor,但我无法让它工作,所以我只是把它打印成Html,因为我需要先解决我的其他问题。

编辑

我已经更改了我的视图,以具有以下代码

<div class="form-group">
                @Html.Raw("<label class='"control-label col-md-2'">Player</label>")
                <div class="col-md-10">
                    @Html.Raw("<input class='"form-control text-box single-line'" name='"model.Players[0].Name'" type-'"text'"")
                </div>
            </div>

因此,该模型现在正确地填充了Players Array,但所有其他值现在都变为null。如果我删除输入元素,值会被填充,但玩家数组再次为空,因为它没有表单字段。你知道罪魁祸首是什么吗?

在TeamViewModel中,我还将Player重命名为Players。

将未知数量的输入元素绑定到MVC5中的模型

为了让MVC将表单数据绑定到Action方法的参数他们的名字应该匹配。

假设你的ViewModel有List<Player> Players的属性,你的代码应该是:

在您的情况下:

foreach (var p in Model.Player)
            {
                <div class="form-group">
                    @Html.Raw("<label class='"control-label col-md-2'">" + p.ToString() + "</label>")
                    <div class="col-md-10">
                        @Html.Raw("<input class='"form-control text-box single-line'" name='"Player'" type-'"text'"")
                    </div>
                </div>
            }

应为:

for (int i = 0; i < Model.Player.Length; i++)
            {
                <div class="form-group">
                    @Html.Raw("<label class='"control-label col-md-2'">" + p.ToString() + "</label>")
                    <div class="col-md-10">
                        @Html.Raw("<input class='"form-control text-box single-line'" name='"model.Player[" + i + "].Name'" type-'"text'"")
                    </div>
                </div>
            }

因为这是您提供的参数的名称:

Create(TeamViewModel model)

还要小心,因为索引不应该被破坏,这意味着它们应该是0、1、2等,而不跳过数字。

我们在属性中读取的方式是通过查找parameterName[index].PropertyName。索引必须从零开始,并且完整的。

注意您可以在Scott Hanselman的文章中阅读更多关于绑定集合的信息-点击此处


最后,我建议如果你有一个属性,它是某个事物的列表——在你的例子中是Player的列表——那么用复数形式表示属性名称——Players

编辑

尝试删除名称前面的"model."。把它做成这样的"Players[0].Name"。由于你的Create Action方法中只有一个参数,所以应该没问题。

我建议您使用助手@Html.EditorFor,因此要做到这一点,您将创建一个部分视图,该视图将用作嵌套属性输入的模板。参见示例:

Shared/EditorTemplates/Player.cshtml

@model Player
<div class="form-group">
    @Html.HiddenFor(e => e.Id)
    @Html.HiddenFor(e => e.TeamId)
    <label class="control-label col-md-2" for="player">Player</label>
    <div class="col-md-10">
          @Html.TextBoxFor(e => e.Name, new { @class = "form-control text-box single-line", id = "player", name = "Player"})
    </div>
</div>    

玩家在团队视图中形成:

 @Html.EditorFor(e => e.Player)

而不是:

 foreach (var p in Model.Player)
            {
                <div class="form-group">
                    @Html.Raw("<label class='"control-label col-md-2'">" + p.ToString() + "</label>")
                    <div class="col-md-10">
                        @Html.Raw("<input class='"form-control text-box single-line'" name='"Player'" type-'"text'"")
                    </div>
                </div>
            }

有关编辑器模板的更多信息,请参阅本文:编辑器和显示模板