2011-02-04 17 views
6

Ho un Page.cshtml simile al seguente (che non funziona):C'è un modo per rendere una @section facoltativa con asp.net mvc Razor ViewEngine?

@{ 
    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> 
    } 
} 

Come ho già detto, questo non funziona. Non voglio definire la sezione se non c'è niente nella collezione. C'è un modo per avere qualcosa come questo lavoro? In caso contrario, quali sono le mie altre opzioni? Sono molto nuovo a questo Razor ViewEngine.

Modifica

Nel mio layout ho:

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

quello che non voglio è il div per l'uscita quando la sezione è vuota.

risposta

3

ho finito per fare qualcosa di un po 'hacky per farlo funzionare come ne avevo bisogno.

sulla mia pagina ho:

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

poi nel mio layout ho:

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

Se la sezione è definito deve essere reso, ma se non c'è contenuti io non voglio the <div> s

Se c'è un modo migliore mi piacerebbe sapere.

+0

Sfortunatamente questa è probabilmente la migliore opzione al momento. Un'altra opzione possibile è provare e chiamare direttamente DefineSection, che è ciò che "@section" viene tradotto in. Il problema è che non puoi inserire Markup in un lambda in Razor v2 (qualcosa che stiamo guardando per il futuro), quindi dovrai definire il tuo contenuto in un costrutto @helper e chiamare quell'helper dal lambda DefineSection . Alla fine, potrebbe finire per essere più facile farlo nel modo che hai. Ma guarderemo a migliorare questo nelle versioni future! –

-1

Puoi avvolgere tutta la sezione in un'istruzione if con IsSectionDefined

Layout.cshtml:

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

tua pagina 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> 
    } 
} 
+0

si vuole mettere l'IsSectionDefined nel file di layout e chiamare rendersection con richiesta = false – ajma

+0

questo è quello che ho attualmente, ma è emettendo il div perché la sezione è definita anche se non c'è nulla in essa. –

+0

Cosa succede se i div attorno ad esso sono avvolti con IsSectionDefined? – ajma

2

Il renderer si aspetta che il metodo venga chiamato a volte nel file di layout. È possibile eseguire lo spoofing del renderer e utilizzare condizionali "globali" (si pensi al login).

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

metodo di estensione con le informazioni campo di sola lettura statica privata per 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); 
     } 
    } 
} 

Nel vostro cshtml:

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

Sì, sì, sì .... lo so ... cattiva riflessione! Usare a proprio rischio :)

0

Io uso il seguente metodo nella mia classe di vista di base (da questo ottimo post 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); 
} 

Se non si dispone di una classe di vista di base, vi consiglio uno perché ti consente di aggiungere ogni sorta di funzionalità in più alle tue visualizzazioni.Basta creare una classe con la seguente firma: public abstract class MyViewPage<T> : WebViewPage<T> e quindi impostare nel tuo web.config:

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