SHARE
TWEET

Nansen Html.DisplayForWithPrefix

a guest Nov 8th, 2014 84 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. namespace Nansen {
  2.   public static class DisplayExtensions {
  3.     public const string DEFAULT_PREFIX_VIEW_FORMAT = "{0}.{1}";
  4.     public const string DIRECTORY_PREFIX_VIEW_FORMAT = "{0}/{1}";
  5.  
  6.     /// <summary>
  7.     /// <see cref="System.Web.Mvc.Html.DisplayExtensions.DisplayFor{TModel,TValue}(System.Web.Mvc.HtmlHelper{TModel},System.Linq.Expressions.Expression{System.Func{TModel,TValue}})"/>
  8.     /// overload using a template prefix. Used to display for the value type using a custom prefix so one object type can have different templates. Will fall back to base types.
  9.     /// </summary>
  10.     /// <remarks>
  11.     /// Works similar to regular <see cref="System.Web.Mvc.Html.DisplayExtensions.DisplayFor{TModel,TValue}(System.Web.Mvc.HtmlHelper{TModel},System.Linq.Expressions.Expression{System.Func{TModel,TValue}})"/>
  12.     /// where the template type is searched recursively using <see cref="Type.BaseType"/>. If no template can be found, it will fallback to the default System.Web.Mvc.Html.DisplayExtensions.DisplayFor method
  13.     /// using no template at all.
  14.     /// </remarks>
  15.     /// <typeparam name="TModel">The model type</typeparam>
  16.     /// <typeparam name="TValue">The value type</typeparam>
  17.     /// <param name="html">The html helper</param>
  18.     /// <param name="expression">The value expression</param>
  19.     /// <param name="templatePrefix">The template prefix, ex using "MyStringList" for <typeparamref name="TValue"/> string would, using default <paramref name="viewFormat" />, look for the display template named MyStringList.string.cshtml</param>
  20.     /// <param name="viewFormat">How to format the view template name, format arguments: {0} - <paramref name="templatePrefix"/>, {1} - model type name. / can also be used to make the prefix be a directory</param>
  21.     /// <param name="fallbackTemplate">If set, will be used if no display template can be found, otherwise DisplayFor without template will be called as fallback</param>
  22.     /// <param name="preferInterfaceBeforeBaseClass">If true, the display template search prefers interfaces before base classes, otherwise all base classes will be checked before any interface. Also, only interfaces defined directly on the current type being searched is considered each <see cref="Type.BaseType"/> iteration</param>
  23.     /// <returns>The rendered html</returns>
  24.     public static MvcHtmlString DisplayForWithPrefix<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string templatePrefix,
  25.       string viewFormat = DEFAULT_PREFIX_VIEW_FORMAT, string fallbackTemplate = null, bool preferInterfaceBeforeBaseClass = false)
  26.     {
  27.       var metaData = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
  28.       var modelType = metaData.Model.GetType(); // this is the most derived type of the model
  29.  
  30.       Func<string, MvcHtmlString> renderer = templateName => System.Web.Mvc.Html.DisplayExtensions.DisplayFor(html, expression, templateName);
  31.  
  32.       // first, check all concrete implementations
  33.       while(modelType != null) {
  34.         var viewName = string.Format(viewFormat, templatePrefix, modelType.Name);
  35.  
  36.         if(DisplayTemplateExist(html.ViewContext, viewName)) {
  37.           return renderer(viewName);
  38.         }
  39.  
  40.         if(preferInterfaceBeforeBaseClass) {
  41.           // check interfaces defined on the model type directly
  42.           var exceptions = modelType.BaseType != null ? modelType.BaseType.GetInterfaces() : Enumerable.Empty<Type>();
  43.           foreach(var @interface in metaData.Model.GetType().GetInterfaces().Except(exceptions)) {
  44.             viewName = string.Format(viewFormat, templatePrefix, @interface.Name);
  45.             if(DisplayTemplateExist(html.ViewContext, viewName)) {
  46.               return renderer(viewName);
  47.             }
  48.           }
  49.         }
  50.  
  51.         modelType = modelType.BaseType;
  52.       }
  53.  
  54.       // check all interfaces, if not already checked per implementation
  55.       if(!preferInterfaceBeforeBaseClass) {
  56.         foreach(var @interface in metaData.Model.GetType().GetInterfaces()) {
  57.           var viewName = string.Format(viewFormat, templatePrefix, @interface.Name);
  58.           if(DisplayTemplateExist(html.ViewContext, viewName)) {
  59.             return renderer(viewName);
  60.           }
  61.         }
  62.       }
  63.  
  64.       // fallback
  65.       return renderer(fallbackTemplate);
  66.     }
  67.  
  68.     private static bool DisplayTemplateExist(ViewContext context, params string[] templateNames)
  69.     {
  70.       foreach(var templateName in templateNames) {
  71.         // the FindPartialView will not automatically search the displaytemplates folder, but the DisplayFor method will
  72.         var viewResult = ViewEngines.Engines.FindPartialView(context, "DisplayTemplates/" + templateName);
  73.         return viewResult.View != null;
  74.       }
  75.       return false;
  76.     }
  77.   }
  78. }
RAW Paste Data
Top