In case you did not know: DisplayModes are awesome and I think we should consider to use them more. This example will show you how you can create your own displaymode and understand the potential of this feature.
I think everyone has found themselves in a situation where a particular component can be reused in another part of a site. However, the presentation should differ and possibly you end op copying the logic and presentation which is something you should always want to prevent as programmer. Here I present you one of the possibilities to consider: DisplayModes.
DisplayModes are classes that help ViewEngines locate specific views in a specific situation. The default DisplayMode shipped with MVC enables you to create custom views for mobile devices. So where you have, for instance, a /Views/Product/Index.cshtml, you can add a /Views/Products/Index.mobile.cshtml which will be chosen if you visit the application with a mobile device. For a complete explanation you could visit:
http://build-failed.blogspot.nl/2012/03/aspnet-mvc-4-part-2-mobile-features.html
I aim to create a DisplayMode which will append the current placeholder to the filename. I have a controller rendering "Title" added to a col-12 and another to a col-6 placeholder. By default the /Views/Common/Title.cshtml view will be used, which renders a <h1> tag, but for the col-6 placeholder I want to render a <h2> tag. Ofcourse there are other ways to achieve this but for now this will do. To start off I created the PlaceholderDisplayMode, implementing IDisplayMode:
public class PlaceholderDisplayMode : IDisplayMode { public bool CanHandleContext(System.Web.HttpContextBase httpContext) { throw new NotImplementedException(); } public string DisplayModeId { get { throw new NotImplementedException(); } } public DisplayInfo GetDisplayInfo(System.Web.HttpContextBase httpContext, string virtualPath, Func<string, bool> virtualPathExists) { throw new NotImplementedException(); } }
So we need to:
The CanHandle method will check 2 things:
private RenderingContext _renderingContext; public bool CanHandleContext(System.Web.HttpContextBase httpContext) { //Is it an Sitecore MVC route? var isContentUrl = httpContext.Items["sc::IsContentUrl"] as string; if (string.IsNullOrEmpty(isContentUrl) || !isContentUrl.ToBool()) return false; //Is there a rendering to get the placeholder from? _renderingContext = RenderingContext.CurrentOrNull; return _renderingContext != null; }
Next I create 2 methods that will help determine the modified virtualPath and check if the (virtual) file exists before returning a new DisplayInfo object or null:
public DisplayInfo GetDisplayInfo(HttpContextBase httpContext, string virtualPath, Func<string, bool> virtualPathExists) { var filePath = TransformPath(virtualPath); if (filePath != null && virtualPathExists(filePath)) return new DisplayInfo(filePath, this); return null; } private string TransformPath(string virtualPath) { var placeholderName = GetFriendlyPlaceholderName(); //if we do not have a place holder, return originalPath if (string.IsNullOrEmpty(placeholderName)) return virtualPath; var extension = Path.GetExtension(virtualPath); //return virualpath as: {virtualPath}.{placeholder}.{extension} return Path.ChangeExtension(virtualPath, placeholderName + extension); } /// /// Gets the placeholdername from current RenderingContext /// Removes any guids generated by dynamic placeholders /// ///private string GetFriendlyPlaceholderName() { var placeholderName = string.Empty; //get last segment from placeholder path if (_renderingContext != null) { placeholderName = (_renderingContext.Rendering.Placeholder + "").Split('/').Last(); //remove guid from dynamic placeholders placeholderName = Regex.Replace(placeholderName, @"_[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}", string.Empty, RegexOptions.IgnoreCase); } return placeholderName; }
Note that I remove guids because I make use of DynamicPlaceholders.
The last thing to do is return a DisplayModeId so the view location can be properly put in the location cache:
public string DisplayModeId { get { GetFriendlyPlaceholderName(); } }
The DisplayMode is finished and after we have registered the Mode on startup the placeholder specific views are used.
DisplayModeProvider.Instance.Modes.Insert(0, new PlaceholderDisplayMode());
And the result (set h2 to render in red to highlight the difference):