我对使用 WPF/Silverlight 的 MVVM 相当满意,但这是我第一次尝试 MVC Web 应用程序……仅供引用。
我创建了一个名为 TestSitesController 的 Controller ,它是从我的 Entity Framework 模型(生成读/写操作和 View 的模板)中的“站点”模型类自动生成的。我唯一修改的地方是在 3 个地方有一个默认参数 Guid id = null 对于某些方法。我刚刚摆脱了“= null”,一切正常。这是我更改的示例
public ActionResult Delete(Guid id = null)
{
//....
}
这里改成了
public ActionResult Delete(Guid id)
{
//....
}
Site 模型没有什么特别的 SiteId、Abbreviation 和 DisplayName ……试图让这个问题尽可能简单。好的,我运行该网站并转到 htpp://.../TestSites/,一切正常。
我注意到我所有的 View (创建、删除、详细信息和编辑)都使用 @model MVCWeb.MyEntities.Site,我现在完全可以接受;但在 Index.cshtml View 中我注意到它使用的是
@model IEnumerable<MVCWeb.MyEntities.Site>
这对于生成的模板来说效果很好,但我想使用“复合 View 模型”,也许这是我试图混合我的 MVVM 知识的地方,但如果可能的话我会坚持下去。在我看来,复合 View 模型只是一个特定于由 1 个或多个实体模型以及其他属性(如 SelectedSiteId 等)组成的 View 的模型。
所以我创建了一个名为 TestSitesViewModel 的非常简单的 ViewModel
public class TestSitesViewModel
{
//Eventually this will be added to a base ViewModel to get rid
//of the ViewBag dependencies
[Display(Name = "Web Page Title")]
public string WebPageTitle;
public IEnumerable<MVCWeb.MyEntities.Site> Sites;
//Other Entities, IEnumberables, or properties go here
//Not important for this example
}
然后在我的 Controller 中我添加了一个名为 IndexWithViewModel 的操作方法
public ActionResult IndexWithViewModel()
{
var vm = new TestSitesViewModel();
vm.WebPageTitle = "Sites With Composite View Model";
vm.Sites = db.Sites.ToList();
return View(vm);
}
然后我复制了一个 Index.cshtml 并将其命名为 IndexWithModel.cshtml 以匹配我的新 ActionResult 方法名称。我改变了顶行
@model IEnumerable<MVCWeb.MyEntities.Site>
到
@model MVCWeb.Models.TestSitesViewModel
我在表格部分之前添加了这个来测试 DisplayNameFor 和 DisplayFor
@Html.DisplayNameFor(model => model.WebPageTitle)
@Html.DisplayFor(model => model.WebPageTitle)
<br />
改变了
@foreach (var item in Model) {
到
@foreach (var item in Model.Sites) {
并暂时注释掉包含所有表头的 tr 部分。除了@Html.DisplayNameFor 正在显示“WebPageTitle”的变量名称而不是使用“网页标题”之外,一切都完美无缺,如
中数据注释的显示属性所示[Display(Name = "Web Page Title")]
public string WebPageTitle;
此外,如果我在包含表头信息的 tr 部分中回复评论。我终究无法弄清楚要放入什么我已经尝试过 model.Sites.Abbreviation、model.Sites[0].Abbreviation 和各种其他组合,但出现错误。
<tr>
<th>
@Html.DisplayNameFor(model => model.Abbreviation)
</th>
<th>
@Html.DisplayNameFor(model => model.DisplayName)
</th>
<th></th>
</tr>
那我应该在那里使用什么?我不太确定为什么 model.Sites.Abbreviation 不起作用,因为 Sites 与原始 Index.cshtml 中用作模型的类型完全相同
最佳答案
折腾了几个小时,我终于弄明白了。
第一个问题为了在数据注释中使用显示属性,必须添加获取和设置访问器方法,即使它们只是默认方法。我假设这是因为它们必须只对属性起作用,而不对类的公共(public)数据成员起作用。这是获取
的代码@Html.DisplayNameFor(model => model.WebPageTitle)
正常工作
public class TestSitesViewModel
{
//Eventually this will be added to a base ViewModel to get rid of
//the ViewBag dependencies
[Display(Name = "Web Page Title")]
public string WebPageTitle { get; set; }
//PUBLIC DATA MEMBER WON'T WORK
//IT NEEDS TO BE PROPERTY AS DECLARED ABOVE
//public string WebPageTitle;
public IEnumerable<MVCWeb.MyEntities.Site> Sites;
//Other Entities, IEnumberables, or properties go here
//Not important for this example
}
问题的第二部分是访问 IEnumerable 变量中的元数据。我声明了名为 headerMetadata 的临时变量并使用它而不是尝试通过 IEnumerable 访问属性
@{var headerMetadata = Model.Sites.FirstOrDefault();}
<tr>
<th>
@Html.DisplayNameFor(model => headerMetadata.Abbreviation)
</th>
<th>
@Html.DisplayNameFor(model => headerMetadata.DisplayName)
</th>
...
这确实回避了 headerMetadata 变量何时超出范围的问题?它适用于整个 View 还是仅限于 html 表格标签?我想这是另一个日期的另一个问题。
关于c# - MVC 和 Entity Framework Html.DisplayNameFor 与复合 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15976576/