将未知数量的输入元素绑定到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。
为了让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>
}
有关编辑器模板的更多信息,请参阅本文:编辑器和显示模板