Reinoud van Dalen

June 23, 2015

Custom Sitecore PageEditor views for ViewRenderings and ControllerRenderings

Getting every view PageEditor compliant can be a tricky thing. Getting stuck with this bloated view containing if statements, checking the PageMode.IsPageEditor state a lot. In this situation I think it would be better to have a completely different view to render. This solution helps you with just that!

How it works

With this solution the implementation is rather simple. If there is a PageEditor specific view available and we are in the PageEdit mode, then that view is preferred. If it’s not available or we are not in PageEdit mode then the application reverts to the default.

Take a look at the following example:

undefined

The result in this case would be that SomeRendering.PageEditor.cshtml and AnotherRendering.cshtml are used in PageEdit mode. So all you need to do is add another view and append “.PageEditor” to the name.

Under the hood

For those who do not really want to know how this is fixed, you can skip to the end of the blog where I have a download link for the source code and nuget package.

ControllerRenderings

The whole idea actually started with controller renderings. I am a big fan of these and I already knew about the existence of Mvc DisplayModes. I have also written a blog where I experimented with a PlaceholderDisplayMode.

With this knowledge I came with the idea of making a PageEditorDisplayMode. The concept is simple: When Mvc tries to locate a View it will consider all registered DisplayModes and if one can handle the request then it will try to resolve a context specific view. Below you can find the code for the PageEditorDisplayMode.

public class PageEditorDisplayMode : IDisplayMode
{
public bool CanHandleContext(HttpContextBase httpContext)
{
//Is it an Sitecore MVC route?
var isContentUrl = httpContext.Items["sc::IsContentUrl"] as string;
if (string.IsNullOrEmpty(isContentUrl) || !isContentUrl.ToBool()) return false;

//Are we in PageEditor mode?
return Context.PageMode.IsPageEditor;
}

public DisplayInfo GetDisplayInfo(HttpContextBase httpContext, string virtualPath, Func<string, bool> virtualPathExists)
{
var extension = Path.GetExtension(virtualPath);
var filePath = Path.ChangeExtension(virtualPath, "PageEditor" + extension);

//Return new DisplayInfo if we were able to find a *.PageEditor view
if (filePath != null && virtualPathExists(filePath)) return new DisplayInfo(filePath, this);

return null;
}

public string DisplayModeId
{
get
{
//Return a key to ensure the view is correctly cached in the ViewEngine
return "PageEditor";
}
}
}

I think the code is pretty self-explanatory, I added some comments to specify what happens. The only thing left to do is register the DisplayMode on application startup. For this I created and added a processor to the Initialize pipeline.

ControllerRenderings: Fixed!

Up next: ViewRenderings

So what about these fellows? They are not picked up by DisplayModes so I needed to add an extended ViewRenderer which would do the same check as the DisplayMode.

Below you find the code of the extended ViewRenderer:

public class PageEditorViewRenderer : ViewRenderer
{
public override void Render(TextWriter writer)
{
if (Context.PageMode.IsPageEditor)
{
var extension = Path.GetExtension(ViewPath);
var filePath = Path.ChangeExtension(ViewPath, "PageEditor" + extension);

if (HostingEnvironment.VirtualPathProvider.FileExists(filePath))
ViewPath = filePath;
}

base.Render(writer);
}
}

Very simple extension where I check if a PageEditor specific view file exists and modify the ViewPath accordingly. But we’re not complete yet. In order for Sitecore to use this extended ViewRenderer I also extended and replaced the GetViewRenderer processor:

public class GetPageEditorViewRenderer : GetViewRenderer
{
public override void Process(GetRendererArgs args)
{
base.Process(args);

var viewRendering = args.Result as ViewRenderer;
if (viewRendering != null)
{
args.Result = new PageEditorViewRenderer
{
ViewPath = viewRendering.ViewPath,
Rendering = viewRendering.Rendering
};
}
}
}

Another simple extension where I check if the base processor has resolved a ViewRenderer as result and if so I replace the result with the extended PageEditorViewRenderer.

ViewRenderers: Fixed!

Get me some!

For those who would like the source code:
https://github.com/RvanDalen/Sc.Commons.PageEditor

And for those who would just like to install:
https://www.nuget.org/packages/Sc.Commons.PageEditorView

Drop a line if you like or have any questions.

TAGS: sitecore pageeditor mvc


Comments
Göran

This is a great idea! How about when you do a preview? Will it still use the "pageeditor" file or the "real" one?


Reinoud van Dalen

Hi Göran, thanks man! In preview mode it will revert to the "real" one. Only in PageEdit mode it will try to resolve a PageEditor view.