18

我对使用 WPF/Silverlight 的 MVVM 相当满意,但这是我第一次尝试 MVC Web 应用程序……只是我的背景。

我创建了一个名为 TestSitesController 的控制器,它是从我的实体框架模型(生成读/写操作和视图的模板)中的“站点”模型类自动生成的。我唯一修改的是在 3 个地方,某些方法有一个默认参数 Guid id = null。我刚刚摆脱了“= null”,一切正常。这是我更改的示例

public ActionResult Delete(Guid id = null)
{
    //....
}

这已更改为

public ActionResult Delete(Guid id)
{
    //....
}

Site 模型没有什么特别的 SiteId、Abbreviation 和 DisplayName……试图让这个问题尽可能简单。好的,所以我运行该网站并转到 htpp://.../TestSites/ 并且一切正常。

我注意到我的所有视图(创建、删除、详细信息和编辑)都在使用 @model MVCWeb.MyEntities.Site,我现在完全可以使用它;但在 Index.cshtml 视图中,我注意到它使用的是

@model IEnumerable<MVCWeb.MyEntities.Site>

这适用于生成的模板,但我想使用“复合视图模型”,也许这是我试图混合我的 MVVM 知识的地方,但如果可能的话,我会坚持下去。在我看来,复合视图模型只是一个特定于由 1 个或多个实体模型以及 SelectedSiteId 等附加属性组成的视图的模型。

所以我创建了一个非常简单的 ViewModel,叫做 TestSitesViewModel

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
}

然后在我的控制器中,我添加了一个名为 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”的变量名称而不是使用“Web Page Title”,如数据注释的 Display 属性中所示,一切都运行良好

[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 中的模型使用的类型完全相同

4

2 回答 2

23

在搞砸了几个小时后,我终于弄清楚了。

第一个问题为了在数据注释中使用 Display arrtibute,即使它们只是默认的,也必须添加 get 和 set 访问器方法。我假设这是因为它们只能处理属性而不是类的公共数据成员。这是获取的代码

@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 变量何时超出范围的问题?它可用于整个视图还是仅限于 html 表格标签?我想这是另一个约会的问题。

于 2013-04-12T20:18:24.000 回答
1

我将尝试用我新学到的 MVVM ASP.NET MVC 经验。

而不是调用@Html.DisplayNameFor(model => model.WebPageTitle),尝试使用@Html.DisplayFor(model => model.WebPageTitle). 您似乎正在 IndexWithViewModel 控制器中设置 WebPageTitle 值,该值应该显示在您的视图中。

查看 ASP.NET MVC 的共享模板/Views/Shared/EditorTemplates/Site.cshtml您可以在和处为 DisplayFor/EditorFor 助手设置自定义模板或部分/Views/Shared/DisplayTemplates/Site.cshtml。ASP.NET MVC 将在使用 DisplayFor 和 EditorFor 呈现您的站点对象时自动选择这些模板。

祝你好运!

于 2013-04-12T16:53:05.417 回答