November Happy Hour will be moved to Thursday December 5th.

Joe Bianco
Jul 17, 2013
  17717
(4 votes)

Building EPiServer Templates with MVC Razor Part 2: Block Templates

EPiServer 7 CMS provides full support for creating templates with MVC using the Razor and Web Forms view engines. Part 1 of this series describes how to create Page Templates.  This post describes how to build Block Templates.

Prerequisites

This blog entry assumes you have completed “Building EPiServer Templates with MVC Razor - Part 1: Page Templates” and the prerequisites listed in that post.

Create the Block Type

Now we are going to create a Block Type to enable editors to create navigation blocks, place them on pages, and configure which pages to display within the block.

A Block Type is similar to a Page Type in that it defines properties for a content item. Like pages, blocks can be reused across pages, sites, and channels, but blocks are not addressable via an explicit URL in the browser.

  1. Models > Blocks > Add > New Item… > Installed > Visual C# > EPiServer > Block Type > TopNavBlock.cs
  2. Uncomment the Name property
  3. Change property type and name to PageReference ParentPage
  4. Update Display parameters - Name: Parent Page, Description: Select the parent of the pages you want to display
using System;
using System.ComponentModel.DataAnnotations;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;

namespace BasicMvcSite.Models.Blocks
{
[ContentType(DisplayName = "TopNavBlock", GUID = "4cf7c1b5-3ae8-42a6-8fa1-078e3471bfb5", Description = "")]
public class TopNavBlock : BlockData
{
[CultureSpecific]
[Editable(true)]
[Display(
Name = "Parent Page",
Description = "Select the parent of the pages you want to display.",
GroupName = SystemTabNames.Content,
Order = 1)]
public virtual PageReference ParentPage { get; set; }
}
}

Create the Model

Now we are going to create a Model to hold a collection of pages to render in the navigation. The Model is passed by the Controller to the View for rendering.

  1. Models > Blocks > Add > Class… > TopNavViewModel.cs
  2. Replace the contents of the TopNavViewModel class as in the code snippet below
  3. Resolve PageData using EPiServer.Core
using EPiServer.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EPiServerMvcSite2.Models.Blocks
{
public class TopNavViewModel
{
// The TopNavBlock
public TopNavBlock TopNavBlock { get; private set; }

// The children of the ParentPage specifed in the TopNavBlock
public IEnumerable<PageData> PageChildren { get; set; }

// Constructor
public TopNavViewModel(TopNavBlock topNavBlock, IEnumerable<PageData> pageChildren)
{
TopNavBlock = topNavBlock;
PageChildren = pageChildren;
}
}
}

Create the Controller

Now we are going to create a Controller that will be invoked when blocks of the TopNavBlock Block Type are referenced. The controller gets the children of the page specified in the ParentPage property of the block. The Controller then populates the Model with this data and passes it to the View for rendering.

  1. Controllers > Add > New Item… > Installed > Visual C# > EPiServer > Block Controller (MVC) > TopNavController.cs
  2. Resolve TopNavBlock using <ProjectName>.Models.Blocks;
  3. Replace the contents of the Index() method as in the snippet below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using EPiServer;
using EPiServer.Core;
using EPiServer.Web;
using EPiServer.Web.Mvc;
using EPiServerMvcSite2.Models.Blocks;

namespace EPiServerMvcSite2.Controllers
{
public class TopNavController : BlockController<TopNavBlock>
{
public override ActionResult Index(TopNavBlock currentBlock)
{
var pageChildren = Enumerable.Empty<PageData>();

// Get the content repository
IContentRepository contentRepository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>();

// Get the children of the page specified in the ParentPage property of the block
if (!PageReference.IsNullOrEmpty(currentBlock.ParentPage))
{
pageChildren = contentRepository.GetChildren<PageData>(currentBlock.ParentPage);
}

return PartialView(new TopNavViewModel(currentBlock, pageChildren));
}
}
}

Create the View

Now we will create the view which renders the navigation menu with the pages in the Model.

  1. Create a TopNav folder in Views
  2. Views > TopNav > Add > New Item… > Installed > Visual C# > EPiServer > Block Partial View (MVC Razor) > Index.cshtml
  3. Update the @model statement to <ProjectName>.Models.Blocks.TopNavViewModel
  4. Replace contents of the <div></div> as in the snippet below
  5. Build and run
@using EPiServer.Core
@using EPiServer.Web.Mvc.Html

@model EPiServerMvcSite2.Models.Blocks.TopNavViewModel

<div>
@if (Model.PageChildren.Any()) {
@* Render nav menu items *@
<ul>
@foreach (var page in Model.PageChildren) {
<li>@Html.ContentLink(page)</li>
}
</ul>
}
</div>

Create the Top Navigation Block

Now that we have created the Block Type, Model, View, and Controller, we can create a Top Navigation block.

  1. Build and run the project
  2. Navigate to http://localhost:<Port>/EPiServer/CMS
  3. Login with a Local Administrator account
  4. Assets Pane > Blocks > Global Library > New Block - Name: Top Navigation, Block Type: TopNavBlock, Parent Page: Home
  5. Publish the block

image

Create About and Contact Pages

Now we will create and publish the About and Contact pages as children of the Home page so we have something to render in the Top Navigation block.

Add a Content Area Property to the Page Type

Now we need to add a Content Area property to the Page Type so that the Top Navigation block can be dragged into it by editorial users. A Content Area is simply a property that contains the blocks that editorial users drag into it.

  1. Add the following snippet to the StandardPage Page Type
// Define a Content Area to enable the editor to drop a navigation block into
public virtual ContentArea TopNavContentArea { get; set; }

Add a Section Override to the Standard View

Now we will put a section override block in the Standard View that injects the menu in to the appropriate place in the layout. A section override is analogous to an asp:Content control in web forms. In this case we will render the TopNavContent area in the TopNav section of the layout.

  1. Add a section override to Views/Standard/Index.cshtml after the @model statement as in the snippet below
@using EPiServer.Core
@using EPiServer.Web.Mvc.Html

@model EPiServerMvcSite2.Models.Pages.StandardPage

@* Render the TopNavContentArea property in the TopNav section defined in the layout *@
@section TopNav {

@Html.PropertyFor(m => m.TopNavContentArea)

}


<div>
@Html.PropertyFor(m => m.MainBody)
</div>

Add the Top Navigation Block to Desired Pages

Now we can add the Top Navigation block to the desired pages via the following steps.

  1. Build and run the project
  2. Navigate to http://localhost:<Port>/EPiServer/CMS
  3. Open the Assets pane
  4. Drag the Top Navigation block to the TopNavContentArea
  5. Publish the page

image

Jul 17, 2013

Comments

Janne Tuutti
Janne Tuutti Aug 14, 2013 03:08 PM

Really cool little tutorial about the MVC template, coined together with MS MVC movie tutorial gets you really good headstart on epi mvc development! Thanks a lot!

Michael Crook
Michael Crook Feb 11, 2014 04:34 AM

Subtle changes in 7.5 made this a pain in the but!

Dave Grey
Dave Grey Feb 12, 2014 05:41 PM

Michael > Did you work out how to get it working in 7.5? I'm new to the CMS and can't work out whats gone wrong, keeps crashing out as soon as I drop a block into the nav section.

ranjitvaity
ranjitvaity Oct 14, 2014 11:42 AM

Hello,
Nice article. helped to understand the flow to create a block.
But still facing a issue, I am getting null value in TopNavController in Index mentioned for var "currentBlock".

Please advice!

Thanks,
Ranjit

Please login to comment.
Latest blogs
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog