我是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。
答案 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