【问题标题】:ASP.NET MVC 3 Display Template problemASP.NET MVC 3 显示模板问题
【发布时间】:2011-03-16 19:40:17
【问题描述】:

首先我在 Views > Blog > DisplayTemplates 中有一个显示模板:

@model Domain.Model.BlogPost
<div class="blogSummary">
    @Html.ActionLink(Model.Title, "post", new { Id = Model.PostID }, new { @class = "titleLink" })
    <div class="subInfo">
        Posted by @Model.Author on @Model.PostedDate.ToString("D") | @Model.PostComments.Count
        Comment(s)</div>
    <br />
    <div class="summaryText">
        @Html.Markdown(Model.Body.Length > 300 ? Model.Body.Remove(0, 300) + "..." : Model.Body)
        @Html.ActionLink("(view more)", "post", new { Id = Model.PostID })
    </div>
</div>

那我有一个看法:

@model IEnumerable<Domain.Model.BlogPost>
@{
    ViewBag.Title = "Index";
}
@Html.DisplayFor(x => x, "BlogPostSummary")

但是,我在DisplayFor() 上遇到错误:

传入的模型项 字典是类型 'System.Data.Objects.ObjectSet`1[Domain.Model.BlogPost]', 但是这本词典需要一个模型 “Domain.Model.BlogPost”类型的项目。

我有点难以理解发生了什么。使用显示模板的最佳方式是什么?

【问题讨论】:

    标签: c# asp.net-mvc templates asp.net-mvc-3 razor


    【解决方案1】:

    问题是您试图传入一个 BlogPost 集合,而需要一个 BlogPost。

    试试:

    @Html.DisplayFor(x => x[0], "BlogPostSummary")
    

    或者类似的东西:

    @foreach (var post in Model)
        @Html.Display(post)
    

    注意:我不相信第二个示例是否正确使用了 Html.Display。我怀疑使用部分而不是显示模板会更好地提供代码。

    UIHint

    默认情况下,ASP.NET MVC 依赖命名约定将BlogPost 类链接到显示模板的 BlogPost.cshtml。但是,如果您想使用 CustomBlogPost.cshtml 作为显示模板,则可以通过应用 UIHint 属性来实现。

    public class DomainModel {
        [UIHint("CustomBlogPost")]
        public BlogPost Post { get; set; }
    } 
    

    【讨论】:

    • 有趣。在我拥有的另一个应用程序中,我这样做了@Html.EditorFor(x =&gt; x.Guests),它工作得很好。视图模型的类型为Invite,它的导航属性Guests 的类型为EntityCollection&lt;Guest&gt;。我没有迭代集合;它是自动完成的:/
    • 我的感觉是在这一点上,你应该使用部分而不是显示模板。你有什么理由不这样做吗?
    • 没有理由,我只是在另一个问题中被告知要避免在我的视图中循环遍历集合并使用模板。在此处查看已接受的答案:stackoverflow.com/questions/5070399/… 那是他告诉我使用编辑器和显示模板的地方。
    • 我不知道该功能,但它似乎不适用于显示模板。
    • 是的。我刚刚想通了。这是因为命名约定。当我将显示模板重命名为 BlogPost.cshmtl 时,一切都开始工作了。这很糟糕,因为我不希望它成为默认的显示模板。
    【解决方案2】:

    不妨试试这个

    @Html.DisplayFor(x => x.First(), "BlogPostSummary")
    

    【讨论】:

    • 不知道为什么[UIHint(...)] 在 MVC 5.x 中不起作用,但上述方法起作用。谢谢。
    【解决方案3】:

    我一直在解决同样的问题,我想我可以为您提供更好的解决方案。你可以循环遍历集合,仍然可以让它工作:

    @foreach(var blogPost in Model)
    {
        Html.DisplayFor(x => blogPost, "BlogPostSummary")
    }
    

    在 lambda 表达式的左侧使用变量并不一定要求您在右侧也使用它。 DisplayFor 需要 Expression&lt;Func&lt;TModel, TValue&gt;&gt;。 TModel 是您的模型的类型,例如IEnumerable&lt;BlogPost&gt;,但 TValue 可以是您喜欢的任何类型。因此,只要您有对集合中当前项目的引用,就像上面的 foreach 一样,您就可以忽略 lambda 表达式的左侧。

    (但你必须拥有 TModel。Html.DisplayFor(() =&gt; blogPost, "BlogPostSummary") 不起作用。)

    【讨论】:

    • 是的,我知道我可以以这种方式循环(尽管它看起来很老套,可能更适合部分视图)。我的问题是我喜欢显示模板如何自动检测到它正在传递它的模型类型的集合并隐式地循环/重复。不幸的是,这仅在您使用正确的模板命名约定时才有效。这意味着每种类型只有一个模板,而且每种类型我需要多个模板。不过感谢您的回答!
    • 我现在实际上正在做这样的事情,而上面的语法虽然看起来应该有效,但不会。您将能够进入您的模板,但生成的 html 将永远被渲染。您必须在 Html.DisplayFor() 前面加上 @。通常这会给您带来once in a code block you don't need to prepend statements with '@' 错误,但显然有一些特殊规则.. stackoverflow.com/questions/17412113/…
    【解决方案4】:

    基本上这是因为执行@Html.DisplayFor() 隐含地告诉MVC 要传递的模型是传递视图的模型,即IEnumerable&lt;Domain.Model.BlogPost&gt;

    您需要做的是枚举模型,并显示它们中的每一个:

    @foreach(var blogPost in Model){
    
        Html.RenderPartial("BlogPostSummary", blogPost)
    
    }
    

    确保 BlogPostSummary 位于正确的文件夹中,您应该一切顺利!

    【讨论】:

      猜你喜欢
      • 2011-07-14
      • 2011-07-26
      • 2011-06-29
      • 2011-12-21
      • 1970-01-01
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多