led*_*per 2 c# asp.net-mvc asp.net-mvc-4 asp.net-mvc-viewmodel
简单的问题,但我无法弄清楚缺少什么.我有一个简单的ViewModel(它会变得更大):
public class TigerTrackingViewModel
{
public TigerTrackingViewModel()
{
this.TigerTrail = new TigerTrail();
}
public Guid YouthGuid { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public TigerTrail TigerTrail { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
TigerTrail是一个嵌套对象.以下是所有属性和子属性:
public class TigerTrail
{
public TigerTrail()
{
DoneDate = new DateTime(1950, 01, 01);
TigerTrailRequiredBadges = new Collection<TigerTrailRequiredBadge>();
TigerTrailElectivedBadges = new Collection<TigerTrailElectiveBadge>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<TigerTrailRequiredBadge> TigerTrailRequiredBadges { get; set; }
public virtual ICollection<TigerTrailElectiveBadge> TigerTrailElectivedBadges { get; set; }
//public virtual ICollection<Youth> Youth { get; set; }
public bool? Done { get; set; }
public DateTime? DoneDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
所以它有TigerTrailRequiredBadges:
public class TigerTrailRequiredBadge
{
public TigerTrailRequiredBadge()
{
DoneDate = new DateTime(1950, 01, 01);
TigerTrailRequiredBadgeSubRequirements = new Collection<TigerTrailRequiredBadgeSubRequirement>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<TigerTrailRequiredBadgeSubRequirement> TigerTrailRequiredBadgeSubRequirements { get; set; }
public bool Done { get; set; }
public DateTime DoneDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
并且有TigerTrailRequiredBadgeSubRequirement(s):
public class TigerTrailRequiredBadgeSubRequirement
{
public TigerTrailRequiredBadgeSubRequirement()
{
DoneDate = new DateTime(1950, 01, 01);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string ShortCode { get; set; }
public string Type { get; set; } //Family, Den, Go See It
public string Description { get; set; }
public bool Done { get; set; }
public DateTime DoneDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
回到TigerTrail.cs类,还有Elective Badge类:
public class TigerTrailElectiveBadge
{
public TigerTrailElectiveBadge()
{
DoneDate = new DateTime(1950, 01, 01);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int Number { get; set; }
public string Name { get; set; }
public string Requirement { get; set; }
public bool Done { get; set; }
public DateTime DoneDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
因此,我的ViewModel将提供所有可用的属性.不幸的是,大部分都需要.它很大而且很难看,但我必须让它发挥作用.
在Controller GET方法中:
public ActionResult TigerTrail()
{
var vm = new List<TigerTrackingViewModel>();
var pack = Ctx.CubPacks.FirstOrDefault(x => x.Id == PackId);
var permTrail = Ctx.TigerTrails.FirstOrDefault(x => x.Name.Contains("PERM"));
foreach (var youth in pack.Youths)
{
//if anyone does not have this trail set up, make a new one.
if (youth.TigerTrail == null)
{
youth.TigerTrail = new TigerTrail();
if (youth.TigerTrail.TigerTrailElectivedBadges == null)
{
youth.TigerTrail.TigerTrailElectivedBadges = new Collection<TigerTrailElectiveBadge>();
}
if (youth.TigerTrail.TigerTrailRequiredBadges == null)
{
youth.TigerTrail.TigerTrailRequiredBadges = new Collection<TigerTrailRequiredBadge>();
}
youth.TigerTrail = permTrail;
}
youth.TigerTrail.Name = youth.FirstName + " " + youth.LastName + " Tiger Trail";
vm.Add(new TigerTrackingViewModel
{
FirstName = youth.FirstName,
LastName = youth.LastName,
YouthGuid = youth.YouthGuid,
TigerTrail = youth.TigerTrail
});
}
return View(vm);
}
Run Code Online (Sandbox Code Playgroud)
在post方法中:
[HttpPost]
public ActionResult TigerTrail(List<TigerTrackingViewModel> youths)
{
return View();
}
Run Code Online (Sandbox Code Playgroud)
每次回发都会返回null.这是观点:
@model List<eTrail.Cubs.ViewModels.TigerTrackingViewModel>
@{
ViewBag.Title = "Award Tracking";
Layout = "~/Areas/App/Views/Shared/_BackendDashboard.cshtml";
}
<h1>Award Tracking</h1>
<hr />
<div class="row">
<div class="span12">
@using (Html.BeginForm("TigerTrail", "Awards", FormMethod.Post, new { @class = "form-horizontal" }))
{
for (int i = 0; i < Model.Count; i++)
{
@Html.HiddenFor(x => Model[i].TigerTrail)
foreach (var item in Model[i].TigerTrail.TigerTrailElectivedBadges)
{
@Html.DisplayFor(x => item.Done)
@Html.DisplayFor(x => item.DoneDate)
@Html.DisplayFor(x => item.Id)
@Html.DisplayFor(x => item.Name)
@Html.DisplayFor(x => item.Number)
@Html.DisplayFor(x => item.Requirement)
}
}
<input type="submit" value="submit" />
}
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我添加了所有的HiddenFor字段,因为它被建议他们都需要在那里才能发回.仍然没有运气.如果我在页面上查看源代码,则id/name将如下所示:
<li>
<input id="elec_Done" name="elec.Done" type="checkbox" value="true"><input name="elec.Done" type="hidden" value="false">
<b>Pet Care</b>
Visit a veterinarian or animal groomer
<input id="elec_Number" name="elec.Number" type="hidden" value="43">
<input id="elec_DoneDate" name="elec.DoneDate" type="hidden" value="1/1/1950 12:00:00 AM">
</li>
Run Code Online (Sandbox Code Playgroud)
翻译中迷失了什么?如何将List返回控制器?
编辑
基于两个答案,因为我需要澄清这个问题:在httppost方法中,我应该接收的List是null.
[HttpPost]
public ActionResult TigerTrail(List<TigerTrackingViewModel> youths) //this is what is null on postback.
{
. . . Do work with youths . .
return RedirectToAction(...);
}
Run Code Online (Sandbox Code Playgroud)
我根据你的代码成功地运行了这个.HttpGet方法视图的修复形式如下:
@using (Html.BeginForm("TigerTrail", "Awards", FormMethod.Post, new { @class = "form-horizontal" }))
{
for (int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(x => x[i].FirstName)
for (int j = 0; j < Model[i].TigerTrail.TigerTrailElectivedBadges.Count; ++j)
{
@Html.EditorFor(x => x[i].TigerTrail.TigerTrailElectivedBadges[j].Name)
}
}
<input type="submit" value="submit" />
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以取出已添加的大量集合初始化.(顺便说一下,那里有一个错误 - 该行youth.TigerTrail = permTrail;完全替换了前面的空但初始化的对象.)
简短说明
诀窍是包含您想要使用的所有字段,EditorFor或者HiddenFor其他所有字段都为null/blank/default/empty.这些天不需要为MVC模型绑定初始化集合,如果有什么内容可以自动创建它们(即使用EditorForor的东西HiddenFor).DisplayFor 不会造成往返的价值 ; 如果没有对象的值进行旅行,该对象将不在该集合中; 如果集合中没有项目进行往返,则除非您强制使用空集合,否则集合将不会在回发中存在.
语法也很关键:所有indexing(foo[i].bar[j].baz)都必须在你提供的lambda中(即在右=>括号之前的右侧).如:
@Html.EditorFor(x => x[i].TigerTrail.TigerTrailElectivedBadges[j].Name)
// ^^^ ^^^
Run Code Online (Sandbox Code Playgroud)
为了得到这个工作,你就必须从改变ICollection<T>并Collection<T>以IList<T>和List<T>这样你就可以索引徽章.
更长的解释
正如其他评论者提到的那样,除非您编写自己的模型绑定器,否则将从您的HttpGet方法,通过其视图的形式到HttpPost方法进行往返的唯一数据是:
<input ...>标记是可见的还是隐藏的),以及DefaultModelBinder,这意味着input的name属性必须是在一个特定的格式.这意味着你必须坚持使用类型DefaultModelBinder可以工作,并且要小心EditorFor,HiddenFor之类的,尤其是对于集合的集合.
因此,如果您希望任何TigerTrailViewModel的TigerTrail成员跨越它,您需要指定EditorFor或HiddenFor为每个成员指定.您不需要对象本身的隐藏字段(例如@Html.HiddenFor(x => x.TigerTrail),您确实需要其他成员的字段,您希望在另一侧看到它们.如果您想要TigerTrails的选择性徽章列表,那么每个你想看到徽章的领域,你必须确保这些字段EditorFor或HiddenFor以及使用上述语法.
作为脚注,TextBoxFor或任何其他xxxxFor方法也可以正常工作,只要类型匹配.
为什么你必须把所有东西放在lambda(右边=>)?这取决于MVC对表达式树的使用,除非你非常感兴趣,否则它们可能不值得担心,但是:你在调用EditorFor或类似内容中提供的lambda 变成了一个表达式树而不是一个委托,而MVC解析了这个编译器生成的数据结构在运行时计算出如何为name它创建的输入写出属性,以便以后可以读回.
如果你使用EditorFor如:
@Html.EditorFor(x => x[i].TigerTrail.TigerTrailElectivedBadges[j].Done)
Run Code Online (Sandbox Code Playgroud)
然后MVC将创建输入1a:
<input class="check-box" name="[6].TigerTrail.TigerTrailElectivedBadges[28].Done" type="checkbox" value="true" />
Run Code Online (Sandbox Code Playgroud)
并且该名称语法是MVC所需的语法DefaultModelBinder.
顺便提一下EditorFor,如果你真的想要,你可以用这些名称格式手动生成输入标签,而不是使用等.这对于用户将项目添加到集合的应用程序非常有用,如果您有JavaScript,则可以动态添加相关的表单字段.如果名称格式正确,MVC将在回发时找到它们.
建议(FWIW,可能不多)
MVC与Web窗体不同,因此没有视图状态会自动保存页面上的每个项目供以后使用.这是一件好事,因为它可以加速您的应用程序,从而缩短加载时间并减少不必要的互联网流量.通常,良好的做法是仅包含用户可能更改的数据,或者只需要了解用户提供的其他值(例如,唯一的记录ID,这将帮助您在数据库中找到用户的某些内容)正在努力).
如果你想在回发时显示或使用其他数据,一般来说最好再次查找(基于用户提供的ID等,或者你在隐藏字段中包含的数据等),而不是在往返时不经意地传输它.
因此,如果您的嵌套集合没有在往返中返回,那么除非用户可以编辑该数据,否则无关紧要; 如果你真的需要它,你可以再次将它从数据库中拉出来.
对于某些应用程序(不是最常见的MVC应用程序),当然可以想象您可能希望传输对象的整个状态(例如,如果您无法更改数据库表的多用户不友好模式多个用户可能正在编辑,但您希望通过保存所有值,检查差异并拒绝编辑(如果它们发生冲突)来阻止他们覆盖彼此的工作.在这种情况下,您必须传输往返的所有数据,并且您需要使用HiddenFor正确的语法或您自己设计的其他机制.
| 归档时间: |
|
| 查看次数: |
6770 次 |
| 最近记录: |