C# MVC 和实体框架 Html.DisplayNameFor 与复合 ViewModel
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15976576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MVC and Entity Framework Html.DisplayNameFor with Composite ViewModel
提问by Dan P
I'm fairly comfortable with MVVM using WPF/Silverlight but this is my first attempt at an MVC Web Application…just an fyi for my background.
我对使用 WPF/Silverlight 的 MVVM 相当满意,但这是我第一次尝试 MVC Web 应用程序……只是我背景的参考。
I've created a controller called TestSitesController which was auto generated from from the “Site” model class in my Entity Framework Model (the template that generates the read/write actions and views). The only thing I modified was in 3 spots there was a default parameter of Guid id = null for some methods. I just got rid of the “ = null” all works fine. Here is an example of what I changed
我创建了一个名为 TestSitesController 的控制器,它是从我的实体框架模型(生成读/写操作和视图的模板)中的“站点”模型类自动生成的。我唯一修改的是在 3 个地方,某些方法有一个 Guid id = null 的默认参数。我刚刚摆脱了“= null”,一切正常。这是我更改的示例
public ActionResult Delete(Guid id = null)
{
//....
}
This was changed to
这被改为
public ActionResult Delete(Guid id)
{
//....
}
The Site model is nothing special SiteId, Abbreviation, and DisplayName…trying to keep it as simple as possible for this question. Ok so I run the website and goto htpp://.../TestSites/ and everything works perfectly.
Site 模型没有什么特别之处,SiteId、Abbreviation 和 DisplayName……对于这个问题,它试图使其尽可能简单。好的,所以我运行网站并转到 htpp://.../TestSites/ 一切正常。
I noticed that all of my views (Create, Delete, Details and Edit) are using an @model MVCWeb.MyEntities.Site which I'm perfectly ok with for now; but in the Index.cshtml view I noticed it was using an
我注意到我的所有视图(创建、删除、详细信息和编辑)都在使用 @model MVCWeb.MyEntities.Site,我现在完全可以使用它;但在 Index.cshtml 视图中,我注意到它正在使用
@model IEnumerable<MVCWeb.MyEntities.Site>
This works fine for the generated template but I would like to use a “Composite View Model” and maybe this is where I'm trying to mix in my MVVM knowledge but would to stick with that if all possible. In my mind a Composite View Model is just a Model that is specific towards a view that is composed of 1 or more Entity Models along with additional properties like SelectedSiteId, etc.
这适用于生成的模板,但我想使用“复合视图模型”,也许这就是我试图混合我的 MVVM 知识的地方,但如果可能的话,我会坚持下去。在我看来,复合视图模型只是一个特定于由 1 个或多个实体模型以及 SelectedSiteId 等附加属性组成的视图的模型。
So I created a very simple ViewModel called TestSitesViewModel
所以我创建了一个非常简单的 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
}
Then in my controller I added an action method called IndexWithViewModel
然后在我的控制器中,我添加了一个名为 IndexWithViewModel 的操作方法
public ActionResult IndexWithViewModel()
{
var vm = new TestSitesViewModel();
vm.WebPageTitle = "Sites With Composite View Model";
vm.Sites = db.Sites.ToList();
return View(vm);
}
I then made a copy of the Index.cshtml and named it IndexWithModel.cshtml to match my new ActionResult method name. I changed the top line of
然后我复制了 Index.cshtml 并将其命名为 IndexWithModel.cshtml 以匹配我的新 ActionResult 方法名称。我改变了顶线
@model IEnumerable<MVCWeb.MyEntities.Site>
To
到
@model MVCWeb.Models.TestSitesViewModel
I added this before the table section to test for the DisplayNameFor and the DisplayFor
我在表格部分之前添加了这个以测试 DisplayNameFor 和 DisplayFor
@Html.DisplayNameFor(model => model.WebPageTitle)
@Html.DisplayFor(model => model.WebPageTitle)
<br />
Changed the
改变了
@foreach (var item in Model) {
To
到
@foreach (var item in Model.Sites) {
And commented out the tr section that contains all of the table headers for now. Everything works perfectly except that the @Html.DisplayNameFor is displaying the variable name of “WebPageTitle” instead of using “Web Page Title” as denoted in the Display attribute of the Data Annotation in
并暂时注释掉包含所有表头的 tr 部分。除了@Html.DisplayNameFor 显示“WebPageTitle”的变量名而不是使用“Web Page Title”(如数据注释的 Display 属性中所示)之外,一切正常
[Display(Name = "Web Page Title")]
public string WebPageTitle;
Also if I comment back in the tr section that contains the table header information. I can not for the life of me figure out what to put in I've tried model.Sites.Abbreviation, model.Sites[0].Abbreviation, and various other combinations but get errors.
此外,如果我在包含表头信息的 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>
So what should I use there? I'm not quite sure why model.Sites.Abbreviation doesn't work as Sites is the exact same type that was used as the model in the original Index.cshtml
那么我应该在那里使用什么?我不太确定为什么 model.Sites.Abbreviation 不起作用,因为 Sites 与原始 Index.cshtml 中用作模型的类型完全相同
采纳答案by Dan P
I finally figured this out after messing around for several hours.
折腾了几个小时,终于搞明白了。
1st problem in order to use the Display arrtibute in the Data Anotations a get and set acessor methods must be added even if they are only the default ones. I'm assuming this is because they must only work on properties and not public data members of a class. Here is code to get the
第一个问题,为了在数据注释中使用 Display arrtibute,必须添加 get 和 set acessor 方法,即使它们只是默认方法。我假设这是因为它们只能处理属性而不是类的公共数据成员。这是获取
@Html.DisplayNameFor(model => model.WebPageTitle)
to work correctly
正常工作
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
}
2nd part of problem was accessing the Metadata in an IEnumerable variable. I declared temporary variable called headerMetadata and used it instead of trying to access the properties through the IEnumerable
问题的第二部分是访问 IEnumerable 变量中的元数据。我声明了名为 headerMetadata 的临时变量并使用它而不是尝试通过 IEnumerable 访问属性
@{var headerMetadata = Model.Sites.FirstOrDefault();}
<tr>
<th>
@Html.DisplayNameFor(model => headerMetadata.Abbreviation)
</th>
<th>
@Html.DisplayNameFor(model => headerMetadata.DisplayName)
</th>
...
This does beg the question of when does headerMetadata variable go out of scope? Is it available for the entire view or is it limited to the html table tags? I suppose that's another question for another date.
这确实引出了 headerMetadata 变量何时超出范围的问题?它适用于整个视图还是仅限于 html table 标签?我想这是另一个约会的另一个问题。
回答by Brett
I'll take a stab with my newly learned MVVM ASP.NET MVC experience.
我将尝试一下我新学到的 MVVM ASP.NET MVC 经验。
Instead of calling @Html.DisplayNameFor(model => model.WebPageTitle)
, try using @Html.DisplayFor(model => model.WebPageTitle)
. You appear to be setting the WebPageTitle value in your IndexWithViewModel controller which should show up in your view.
与其调用@Html.DisplayNameFor(model => model.WebPageTitle)
,不如尝试使用@Html.DisplayFor(model => model.WebPageTitle)
. 您似乎正在您的 IndexWithViewModel 控制器中设置 WebPageTitle 值,该值应该显示在您的视图中。
Look into shared templatesfor ASP.NET MVC. You can set up custom templates or partials for DisplayFor/EditorFor helpers at /Views/Shared/EditorTemplates/Site.cshtml
and /Views/Shared/DisplayTemplates/Site.cshtml
. ASP.NET MVC will automatically pick up on those templates when rendering your Site object with DisplayFor and EditorFor.
查看ASP.NET MVC 的共享模板。您可以在/Views/Shared/EditorTemplates/Site.cshtml
和为 DisplayFor/EditorFor 助手设置自定义模板或部分/Views/Shared/DisplayTemplates/Site.cshtml
。当使用 DisplayFor 和 EditorFor 呈现您的站点对象时,ASP.NET MVC 将自动选取这些模板。
Good luck!
祝你好运!