3

We are gradually migrating a Spark based project to use Razor and I have come across something I can't seem to find an answer to.

My line in my Spark master calls a sub View like so

<Sidebar>   
    <segment name="header"> 
        <div> <!-- header content--> </div>
    </segment>
    <segment name="content"> 
        <div> <!-- content content--> </div>
    </segment>
</Sidebar>

The Sidebar spark looks like so

<div id="sidebar" >
<div class="header">
    <render segment="header">
        <!-- placeholder -->
    </render>
</div>
<div class="ui-layout-content content">
    <render segment="content">
        <!-- placeholder -->
    </render>   
</div>

This renders with the content from the first section displayed in the layout from the second. Is there some way I can recreate this using Razor. I can see that I need to use Partials, but I can't see how to pass the content into the sidebar subview.

Essentially I'm trying to recreate the functionality that Spark calls Segments (or previously Sections) http://sparkviewengine.com/reference/elements#segmentpreviouslyknownassection

EDIT: More information. I have an Index.cshtml that gets it's layout from Application.cshtml. In here I have the markup code that goes into the Sidebar.cshtml partial.

If I add put @section header (which is rendered in the Sidebar.cshtml) in my Index.cshtml file it doesn't recognise it as a valid section. I have @RenderSection("header", false) in my Sidebar.cshtml file.

How do I tie these 2 together?

So my hierarchy is as follows

Application.cshtml -- Global page layout
Index.cshtml -- Page layout including content for the sidebar
Sidebar.cshtml -- Template / layoout for sidebar content from Index.cshtml

For example

in Index.cshtml

    @RenderPage("Sidebar") 
    @section SidebarHeader { <!--Title or something --> }
    @section SidebarContent { <!--Content --> }

Then in Sidebar.cshtml

    <div class="header">
        @RenderSection("SidebarHeader", false)
    </div>
    <div class="ui-layout-content content">
        @RenderSection("SidebarContent", false)
    </div>

The idea is that I can have a template in a sub-view that is populated with the content from the view. Meaning that I can template areas for other pages across the site. Eg. The sidebar content on another page will need the same format, but different content.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Dave
  • 2,552
  • 5
  • 25
  • 30

2 Answers2

6

You can use Layouts and Sections to accomplish the same. See details here: http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx

Index.cshtml:

@RenderSection("Sidebar")

Your sidebar.cshtml would look like this:

<div id="sidebar" >
    <div class="header">
        @RenderSection("header", required: false)
    </div>
    <div class="ui-layout-content content">
        @RenderSection("content", required: false)  
    </div>
</div>

And sub view(s) like this (you can define them in one too but having them separate is probably better in the long term):

SubViews.cshtml:

    @section header {
      <div> <!-- header content--> </div>

    }

    @section content {
      <div> <!-- content content--> </div>

    }
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • The top level has the content and I need it to display the content according to the template in the Sidebar.spark. The Sidebar.spark file describes the layout of the content from the top layer. Wouldn't I need to move the content to the subview (Sidebar view) if I implement it in this way? – Dave Jul 05 '11 at 16:09
  • Essentially trying to recreate the functionality from http://sparkviewengine.com/reference/elements#segmentpreviouslyknownassection – Dave Jul 05 '11 at 16:17
  • 1
    Yes. You're essentially doing the same with spark too. With the link you mentioned, what is happening is your `sidebar` partial view itself is rendering other sections. I'll update my answer to reflect the same. – Mrchief Jul 05 '11 at 17:01
  • I still don't see how I get the content from the index.cshtml to the sidebar.cshtml. I'll edit the question, perhaps I'm not making my issue clear. Thanks – Dave Jul 06 '11 at 09:19
  • 1
    I think you're question is still not clear. Index can pull content from sidebar. Sidebar cannot pull content from Index. – Mrchief Jul 06 '11 at 14:19
  • Ahh ok I think that might answer it. So I can't use a Partial cshtml file as a reusable template? For example we have a spark that has the template for our lightbox popups, we can use that over the site by using the popup tag. Are you suggesting that this functionality can't be replicated in Razor? – Dave Jul 06 '11 at 14:36
  • 1
    No. Let me put it this way: Application.cshtml -- Global page layout Index.cshtml -- Page layout including content for the sidebar Sidebar.cshtml -- Template / layout for sidebar content from header.cshtml and content.cshmtl. Sidebar, header and content are partial views. – Mrchief Jul 06 '11 at 17:03
  • I see what you mean, but then template isn't resuable, doesn't this mean I can only have one instance in my page of the Sidebar layout? (The sidebar is only one place this pattern has been used, in some cases I need more than one instance of the template on the page) – Dave Jul 06 '11 at 17:06
  • 1
    They are reusable. You can put `@RenderSection("Sidebar")` in as many views as you want. Same goes for header and content. – Mrchief Jul 06 '11 at 17:09
  • Huzzah! I can see what you are getting at now! Thankyou so much for the help. If only I could upvote twice ;) – Dave Jul 06 '11 at 17:10
-1

The only way I can see to make this work as I want is as follows.

Create a class to represent the content from my subview

eg

public class Sidebar
{
    public string Title { get; set; }
    public IHtmlString Contents { get; set; }
}

Then in _viewstart.cshtml

Func<Sidebar, HelperResult> sidebarHelper =
    @<div class="sidebar">
        <div>@item.Title</div>
        <div>
            @item.Contents
        </div>
    </div>;
ViewContext.Controller.ViewData["SidebarTemplate"] = sidebarHelper ;

Then at the top of my Index.cshtml

var sidebarTemplate = ViewContext.Controller.ViewData["SidebarTemplate"] as Func<Sidebar, HelperResult>; 

Which I can call further down like so

@{ 
    var sidebarContents= new StringBuilder(); 
    foreach(var x in y)
    {
        sidebarContents.append("<div>Some Potentially Long nasty HTML STRING" + x.Something + "</div>");
    }
}
@sidebarTemplate (new Sidebar()
{ 
    Title = "title",
    Contents = Html.Raw(sidebarContents.ToString())
})

I don't really like that I have to declare the HTML in the code like this as it could potentially be a long string. Technically thought this does solve the issue. If anyone has any better ideas or if I'm not making myself clear enough please comment! Thanks.

Dave
  • 2,552
  • 5
  • 25
  • 30
  • Marked Mrchief as answer as I've finally understood his answer - Please upvote his answer. – Dave Jul 06 '11 at 17:12