c# - MVC 和 Entity Framework Html.DisplayNameFor 与复合 ViewModel

标签 c# asp.net-mvc-4 .net-4.5 razor-2

我对使用 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)
&nbsp;
@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/

相关文章:

c# - 在 Azure 服务总线中发布到一个主题并订阅另一个主题的集成测试不可靠是否存在竞争条件?

asp.net-mvc - 需要帮助了解 Moq 如何解决实际查询

c# - 条件属性如何工作?

xml - 十六进制值 0X03 是无效字符

c# - 异步/等待与 BackgroundWorker

c# - 有没有办法使用 MEF 指定导入的元数据?

c# - Xamarin.Forms.CarouselView 在 iOS 上不起作用

c# - C#中的单位转换设计模式

c# - C# 中是否可能进行部分泛型类型推断?

security - 如何使用Web API限制DOS攻击