有没有办法用asp.net mvc Razor ViewEngine制作一个@section可选?

时间:2011-02-04 21:47:35

标签: asp.net-mvc razor viewengine

我有一个类似于以下的Page.cshtml(不起作用):

@{
    Layout = "../Shared/Layouts/_Layout.cshtml";
    var mycollection = (ViewBag.TheCollection as IQueryable<MyCollectionType>);
}

<h2>@ViewBag.Title</h2>

content here

@if (mycollection != null && mycollection.Count() > 0)
{    
    @section ContentRight
    {    
        <h2>
            Stuff
        </h2>
        <ul class="stuff">
            @foreach (MyCollectionType item in mycollection )
            {
                <li class="stuff-item">@item.Name</li>
            }
        </ul>
    }
}

正如我所说,这不起作用。如果集合中没有任何内容,我想不定义该部分。有没有办法让这样的工作?如果没有,我的其他选择是什么?我对这款Razor ViewEngine非常陌生。

修改

在我的布局中,我有:

@if(IsSectionDefined("ContentRight")) 
{
    <div class="right">
        RenderSection("ContentRight")
    </div>
}

我不想要的是当该部分为空时输出的div。

5 个答案:

答案 0 :(得分:3)

我最终做了一些有点hacky的事情,让它按照我需要的方式工作。

在我的页面上我有:

@{
    Layout = "../Shared/Layouts/_Layout.cshtml";
    var mycollection = (ViewBag.TheCollection as IQueryable<MyCollectionType>);
    ViewBag.ShowContentRight = mycollection != null && mycollection.Count() > 0;
}

然后在我的布局中我有:

@if(IsSectionDefined("ContentRight") && (ViewBag.ShowContentRight == null ||ViewBag.ShowContentRight == true)) 
{
    <div class="right">
        RenderSection("ContentRight")
    </div>
}
else if(IsSectionDefined("ContentRight"))
{
    RenderSection("ContentRight")
}

如果定义了部分,则必须进行渲染,但如果没有内容,我不想要<div> s

如果有更好的方式我想知道。

答案 1 :(得分:2)

渲染器期望在布局文件中某个时候调用该方法。您可以欺骗渲染器并使用“全局”条件(想想登录)。

@{
    ViewBag.content = RenderBody();
}
@if (Request.IsAuthenticated) {
        @ViewBag.content;
} 
else {
        @Html.Partial("_LoginPartial")
}

答案 2 :(得分:0)

具有针对perf的私有静态只读字段信息的扩展方法:

private static readonly FieldInfo RenderedSectionsFieldInfo = typeof(WebPageBase).GetField("_renderedSections", BindingFlags.Instance | BindingFlags.NonPublic);

public static void EnsureSectionsAreRegisteredAsRendered(this WebPageBase webPageBase, params string[] sectionNames)
{
    var renderedSections = RenderedSectionsFieldInfo.GetValue(webPageBase) as HashSet<string>;
    if (renderedSections == null)
    {
        throw new WebCoreException("Could not get hashset from private field _renderedSections from WebPageBase");    
    }
    foreach (var sectionName in sectionNames)
    {
        if (!renderedSections.Contains(sectionName))
        {
            renderedSections.Add(sectionName);
        }
    }
}

在你的cshtml中:

@{ this.EnsureSectionsAreRegisteredAsRendered("SectionName1", " SectionName2", "…"); }

是的,是的,是的......我知道......糟糕的反思!使用风险自负:)

答案 3 :(得分:0)

我在我的视图基类中使用以下方法(来自这篇优秀的博文http://haacked.com/archive/2011/03/05/defining-default-content-for-a-razor-layout-section.aspx/):

public HelperResult RenderSection(string name, Func<dynamic, HelperResult> defaultContents)
{
    if (IsSectionDefined(name))
    {
        return RenderSection(name);
    }
    return defaultContents(null);
}

如果您没有视图基类,我推荐一个,因为它可以让您为视图添加各种额外的功能。只需使用以下签名创建一个类:public abstract class MyViewPage<T> : WebViewPage<T>,然后在web.config中设置:

<system.web.webPages.razor>
  <pages pageBaseType="MyViewPage">
    ...
  </pages>
</system.web.webPages.razor>

答案 4 :(得分:-1)

您可以使用IsSectionDefined

将整个部分包装在if语句中

Layout.cshtml:

@if (IsSectionDefined("ContentRight"))
{
    <div>
    @RenderSection(name: "ContentRight", required: false)
    </div>
}

您的cshtml页面:

@section ContentRight
{    
    @if (mycollection != null && mycollection.Count() > 0)
    {   
    <h2>
        Stuff
    </h2>
    <ul class="stuff">
        @foreach (MyCollectionType item in mycollection )
        {
            <li class="stuff-item">@item.Name</li>
        }
    </ul>
    }
}