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

时间:2015-12-27 20:57:39

标签: c# asp.net-mvc-5

我是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假设能够将input元素转换为列表并将其传递给我的ViewModel。但是,我的ViewModel始终为null。

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

P.S。我知道我可以使用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。如果我删除了输入元素,则会填充值,但是player数组再次为null,因为没有表单字段。你知道什么可能是罪魁祸首吗?

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

2 个答案:

答案 0 :(得分:5)

为了让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 ......等而不会跳过一个数字。

  

我们在属性中阅读的方式是寻找   参数名称[索引] .PropertyName。索引必须从零开始   完整。

注意您可以在Scott Hanselman的帖子中阅读有关绑定集合的更多信息 - here

最后我建议如果你有一个属性列表的属性 - 在Player的案例列表中使用复数形式作为属性名称 - Players

修改

尝试删除“模型”。在名字的前面。使它像这样的“玩家[0] .Name”。由于您在Create Action方法中只有一个参数,因此应该没问题。

答案 1 :(得分:0)

我建议你使用帮助器@Html.EditorFor,这样你就可以创建一个局部视图,用作嵌套属性输入的模板。看到例子:

  

共享/ 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>
            }

有关编辑器模板的详细信息,请参阅此文章:Editor and display templates