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

Anders Hattestad
May 25, 2011
  5019
(0 votes)

PageList that lists different page types differently

Often I make a list view where its possible to gather a lot of different pages of different types together. In most projects these pages are displayed in one way. Sometimes I add some logic in the ItemTemplate that turns on and off different areas based on the current item displayed.

But now I have made a version of PageList that will use user controls instead of ItemTemplate. Those user controls need to be marked with an attribute.

Code Snippet
  1. public class FormatListAttribute : PlugInAttribute
  2. {
  3.     public string Url { get; set; }
  4.     public string Key { get; set; }
  5.     public Type[] TriggerOnPageTypes { get; set; }
  6.     public Type[] TriggerOnInnerObject { get; set; }
  7.     public string TriggerOnPropertyIsNotNull { get; set; }
  8. }

These handlers can be a simple user control as this:

 

Code Snippet
  1. [FormatList(DisplayName = "ContainerPageType", SortIndex = 100,
  2.     TriggerOnPageTypes = new Type[] { typeof(ContainerPageType) },
  3.     Url = "/Custom/Units/ListViews/ListFormats/ContainerView.ascx")]
  4. public partial class ContainerView : FormatBaseUserControl
  5. {
  6.     protected void Page_Load(object sender, EventArgs e) { }
  7.     public override void DataBind()
  8.     {
  9.         Childs.DataSource = EPiServer.DataFactory.Instance.GetChildren(CurrentPage.PageLink);
  10.         Childs.DataBind();
  11.         base.DataBind();
  12.     }
  13. }
Code Snippet
  1. <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ContainerView.ascx.cs" Inherits="UDFase1.Custom.Units.ListViews.ListFormats.ContainerView" %>
  2.   <Itera:Property ID="Property12" runat="server"PropertyName="PageLink"
  3.     AddFirst="<h2>" AddLast="</h2>" />
  4. <Itera:Property ID="Property2" runat="server" PropertyName="MainIntro|MainBody:StripHtml(200)" AddFirst="<p>" AddLast="</p>" />
  5. <EPiServer:PageList ID="Childs" runat="server" MaxCount="7" EnableVisibleInMenu=true>
  6.     <ItemTemplate><Itera:Property ID="Property12" runat="server"  PropertyName="PageLink" AddFirst="<nobr>[" AddLast="]</nobr>" /> </ItemTemplate>
  7. </EPiServer:PageList>

This user control will display one page of ContainerPageType with an header, and all its child elements bellow.Like this:

image

while other items can have there own handler.

So its possible to get lists like this:

image

where each “row” is handled by a separate handler.

How

I made myself a web control that inherits from PageList

Code Snippet
  1. public class PageListFormat : PageList
  2. {
  3.     public string FormatMustContainKey { get; set; }
  4.     public Dictionary<PageData, object> InnerObjects { get; set; }
  5.     public Dictionary<PageData, object> ExtraDisplayInfo { get; set; }
  6.     public bool ShowDebug { get; set; }
  7.     protected override void CreateChildControls()
  8.     {

I have opened up for the possibility to have an inner object connected to a page data object. Its also possible to make a handler for that object type if it exits.

Then I loops thro all the registered handlers

Code Snippet
  1. var plugins2 = EPiServer.PlugIn.PlugInLocator.FindPlugInTypes(typeof(FormatListAttribute));
  2. var plugins = new List<PlugInDescriptor>();
  3. foreach (var i in plugins2)
  4.     if (string.IsNullOrEmpty(FormatMustContainKey))
  5.     {
  6.         plugins.Add(i);
  7.     }
  8.     else
  9.     {
  10.         FormatListAttribute att = i.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
  11.         if (!string.IsNullOrEmpty(att.Key) && att.Key.Contains(FormatMustContainKey))
  12.  
  13.         plugins.Add(i);
  14.     }
  15.  
  16. plugins.Sort(SortPlugInDescriptor);

Then its just a question of what handler to use for a given page.

Code Snippet
  1. FormatListAttribute GetHandler(PageData page, List<PlugInDescriptor> plugins, StringBuilder debug, Control control2)
  2. {
  3.     debug.Append("<br />Checking page " + page.PageName);
  4.     foreach (var p in plugins)
  5.     {
  6.         FormatListAttribute att = p.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
  7.         if (InnerObjects != null && att.TriggerOnInnerObject != null && InnerObjects.ContainsKey(page))
  8.         {
  9.             var check = InnerObjects[page];
  10.             debug.Append("<br />Check inner objects" + check);
  11.             foreach (var t in att.TriggerOnInnerObject)
  12.                 if (t.IsInstanceOfType(check))
  13.                     return att;
  14.         }
  15.            
  16.             if (att.TriggerOnPageTypes != null)
  17.         {
  18.             debug.Append("<br />Check page type");
  19.             foreach (var t in att.TriggerOnPageTypes)
  20.                 if (t.IsInstanceOfType(page))
  21.                     return att;
  22.         }
  23.             if (!string.IsNullOrEmpty(att.TriggerOnPropertyIsNotNull) && page.Property[att.TriggerOnPropertyIsNotNull] != null && !page.Property[att.TriggerOnPropertyIsNotNull].IsNull)
  24.             {
  25.                 debug.Append("<br />TriggerOnPropertyIsNotNull");
  26.                 return att;
  27.             }
  28.     }
  29.     return null;
  30. }

so if I make a handler for an event

Code Snippet
  1. [FormatList(DisplayName = "EventView", SortIndex = 20,
  2.     TriggerOnPropertyIsNotNull = "IsTypeEvent",
  3.     Url = "/Custom/Units/ListViews/ListFormats/EventView.ascx")]
  4. public partial class EventView : FormatBaseUserControl
  5. {

all pages with IsTypeEvent checked will be displayed accordingly to the front end code, for instance like this

image

 

The PageList control can look like this

Code Snippet
  1. <Itera:PageListFormat id="PageListFormat1" runat="server">
  2.     <StartTemplate><div></StartTemplate>
  3.     <EndTemplate></div></EndTemplate>
  4.     <ItemTemplate>
  5.         <div>Not handled</div>
  6.     </ItemTemplate>
  7. </Itera:PageListFormat>

 

to load another ITemplate using code is very easy, just load it like this

Code Snippet
  1. var handlerTemplate = this.Page.LoadTemplate(handler.Url);

 

Trying to add the code but having difficulties to add it to the code section. But guess it will be available soon here

In the mean time the files are available here

There is only 3 files here

PageListFormat.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using EPiServer.Web.WebControls;
  6. using EPiServer.Core;
  7. using System.Web.UI;
  8. using EPiServer.PlugIn;
  9. using System.Web.UI.WebControls;
  10. using Itera.PageListWithFormat;
  11. using System.ComponentModel;
  12. using System.Collections;
  13.  
  14. namespace Itera.WebControls
  15. {
  16.  
  17.     public class PageListFormat : PageList
  18.     {
  19.         public string FormatMustContainKey { get; set; }
  20.         public Dictionary<PageData, object> InnerObjects { get; set; }
  21.         public Dictionary<PageData, object> ExtraDisplayInfo { get; set; }
  22.         public bool ShowDebug { get; set; }
  23.         protected override void CreateChildControls()
  24.         {
  25.             PageDataCollection pages = base.GetPages();
  26.             if (pages.Count == 0)
  27.             {
  28.                 return;
  29.             }
  30.             StringBuilder debug = new StringBuilder();
  31.  
  32.             PageData page = null;
  33.             if (!PageReference.IsNullOrEmpty(this.PageLink))
  34.             {
  35.                 page = this.GetPage(this.PageLink);
  36.             }
  37.             if (this.HeaderTemplate != null)
  38.             {
  39.                 Control control = new PageTemplateContainer(page);
  40.                 this.HeaderTemplate.InstantiateIn(control);
  41.                 this.Controls.Add(control);
  42.             }
  43.             this.PreparePagingControls(pages);
  44.             var plugins2 = EPiServer.PlugIn.PlugInLocator.FindPlugInTypes(typeof(FormatListAttribute));
  45.             var plugins = new List<PlugInDescriptor>();
  46.             foreach (var i in plugins2)
  47.                 if (string.IsNullOrEmpty(FormatMustContainKey))
  48.                 {
  49.                     plugins.Add(i);
  50.                 }
  51.                 else
  52.                 {
  53.                     FormatListAttribute att = i.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
  54.                     if (!string.IsNullOrEmpty(att.Key) && att.Key.Contains(FormatMustContainKey))
  55.  
  56.                         plugins.Add(i);
  57.                 }
  58.  
  59.             plugins.Sort(SortPlugInDescriptor);
  60.             debug.Append("<div style='clear:both;'><table>");
  61.             foreach (var p in plugins)
  62.             {
  63.                 FormatListAttribute att = p.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
  64.                 debug.Append("<tr><td>" + att.DisplayName + "</td><td>" + att.SortIndex + "</td></tr>");
  65.  
  66.             }
  67.             debug.Append("</table><ul>");
  68.  
  69.             for (int i = 0; i < pages.Count; i++)
  70.             {
  71.                 Control control2 = CreateTemplateContainer(pages, i);
  72.                 debug.Append("<li>Page " + i + " " + pages[i].PageName + " [" + pages[i] + "]");
  73.                 CreateTemplate(debug, pages, plugins, i, control2);
  74.                 debug.Append("</li>");
  75.             }
  76.             debug.Append("</ul></div>");
  77.             if (this.FooterTemplate != null)
  78.             {
  79.                 Control control3 = new FormatTemplateContainer(page);
  80.                 this.FooterTemplate.InstantiateIn(control3);
  81.                 this.Controls.Add(control3);
  82.             }
  83.             this.CreatePagingControls(pages);
  84.             if (ShowDebug)
  85.                 this.Controls.Add(new Literal() { Text = debug.ToString(), ID = "Debug" });
  86.         }
  87.  
  88.         private Control CreateTemplateContainer(PageDataCollection pages, int i)
  89.         {
  90.             object innerObject = null;
  91.             if (InnerObjects != null && InnerObjects.ContainsKey(pages[i]))
  92.                 innerObject = InnerObjects[pages[i]];
  93.             object extraInfo = null;
  94.             if (ExtraDisplayInfo != null && ExtraDisplayInfo.ContainsKey(pages[i]))
  95.                 extraInfo = ExtraDisplayInfo[pages[i]];
  96.             Control control2 = new FormatTemplateContainer(pages[i], innerObject, extraInfo);
  97.             return control2;
  98.         }
  99.  
  100.         private void CreateTemplate(StringBuilder debug, PageDataCollection pages, List<PlugInDescriptor> plugins, int i, Control control2)
  101.         {
  102.             var handler = GetHandler(pages[i], plugins, debug, control2);
  103.             if (handler != null)
  104.             {
  105.                 if (StartTemplate != null)
  106.                 {
  107.                     Control start = new FormatTemplateContainer(pages[i]);
  108.                     StartTemplate.InstantiateIn(start);
  109.                     this.Controls.Add(start);
  110.                 }
  111.                 debug.Append("<br />Found handler " + handler.Url);
  112.                 var handlerTemplate = this.Page.LoadTemplate(handler.Url);
  113.                 if (handlerTemplate is EPiServer.UserControlBase)
  114.                 {
  115.                     (handlerTemplate as EPiServer.UserControlBase).CurrentPage = pages[i];
  116.                 }
  117.  
  118.                 handlerTemplate.InstantiateIn(control2);
  119.                 this.Controls.Add(control2);
  120.  
  121.                 if (EndTemplate != null)
  122.                 {
  123.                     Control end = new FormatTemplateContainer(pages[i]);
  124.                     EndTemplate.InstantiateIn(end);
  125.                     this.Controls.Add(end);
  126.                 }
  127.             }
  128.             else
  129.             {
  130.                 debug.Append("<br />using default");
  131.                 this.ItemTemplate.InstantiateIn(control2);
  132.                 this.Controls.Add(control2);
  133.             }
  134.         }
  135.  
  136.         FormatListAttribute GetHandler(PageData page, List<PlugInDescriptor> plugins, StringBuilder debug, Control control2)
  137.         {
  138.             debug.Append("<br />Checking page " + page.PageName);
  139.             foreach (var p in plugins)
  140.             {
  141.                 FormatListAttribute att = p.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
  142.                 if (InnerObjects != null && att.TriggerOnInnerObject != null && InnerObjects.ContainsKey(page))
  143.                 {
  144.                     var check = InnerObjects[page];
  145.                     debug.Append("<br />Check inner objects" + check);
  146.                     foreach (var t in att.TriggerOnInnerObject)
  147.                         if (t.IsInstanceOfType(check))
  148.                             return att;
  149.                 }
  150.  
  151.                 if (att.TriggerOnPageTypes != null)
  152.                 {
  153.                     debug.Append("<br />Check page type");
  154.                     foreach (var t in att.TriggerOnPageTypes)
  155.                         if (t.IsInstanceOfType(page))
  156.                             return att;
  157.                 }
  158.                 if (!string.IsNullOrEmpty(att.TriggerOnPropertyIsNotNull) && page.Property[att.TriggerOnPropertyIsNotNull] != null && !page.Property[att.TriggerOnPropertyIsNotNull].IsNull)
  159.                 {
  160.                     debug.Append("<br />TriggerOnPropertyIsNotNull");
  161.                     return att;
  162.                 }
  163.             }
  164.             return null;
  165.         }
  166.  
  167.  
  168.         [PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(FormatTemplateContainer)), Browsable(false)]
  169.         public ITemplate StartTemplate { get; set; }
  170.         [PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(FormatTemplateContainer)), Browsable(false)]
  171.         public ITemplate EndTemplate { get; set; }
  172.         public static int SortPlugInDescriptor(PlugInDescriptor a, PlugInDescriptor b)
  173.         {
  174.             int aN = a.GetAttribute(typeof(FormatListAttribute)).SortIndex;
  175.             int bN = b.GetAttribute(typeof(FormatListAttribute)).SortIndex;
  176.             return aN.CompareTo(bN);
  177.         }
  178.     }
  179. }

 

 

FormatListAttribute.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using EPiServer.PlugIn;
  6.  
  7. namespace Itera.PageListWithFormat
  8. {
  9.     
  10. public class FormatListAttribute : PlugInAttribute
  11. {
  12.     public string Url { get; set; }
  13.     public string Key { get; set; }
  14.     public Type[] TriggerOnPageTypes { get; set; }
  15.     public Type[] TriggerOnInnerObject { get; set; }
  16.     public string TriggerOnPropertyIsNotNull { get; set; }
  17. }
  18. }

 

FormatBaseUserControl.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using EPiServer.Web.WebControls;
  6. using EPiServer.Core;
  7. using System.Web.UI;
  8.  
  9. namespace Itera.PageListWithFormat
  10. {
  11.     public class FormatTemplateContainer : PageTemplateContainer
  12.     {
  13.         public FormatTemplateContainer(PageData page)
  14.             : base(page)
  15.         {
  16.  
  17.         }
  18.         public FormatTemplateContainer(PageData page, object innerObject, object extraDisplay)
  19.             : base(page)
  20.         {
  21.             InnerObject = innerObject;
  22.             ExtraDisplayInfo = extraDisplay;
  23.         }
  24.         public object InnerObject { get; set; }
  25.         public object ExtraDisplayInfo { get; set; }
  26.  
  27.     }
  28.  
  29.     public class FormatBaseUserControl : EPiServer.UserControlBase
  30.     {
  31.         public new PageData CurrentPage
  32.         {
  33.             get
  34.             {
  35.                 if (this.Parent is FormatTemplateContainer)
  36.                     return (this.Parent as FormatTemplateContainer).CurrentPage;
  37.                 return null;
  38.             }
  39.         }
  40.         public object InnerObject
  41.         {
  42.             get
  43.             {
  44.                 if (this.Parent is FormatTemplateContainer)
  45.                     return (this.Parent as FormatTemplateContainer).InnerObject;
  46.                 return null;
  47.             }
  48.         }
  49.         public object ExtraDisplayInfo
  50.         {
  51.             get
  52.             {
  53.                 if (this.Parent is FormatTemplateContainer)
  54.                     return (this.Parent as FormatTemplateContainer).ExtraDisplayInfo;
  55.                 return null;
  56.             }
  57.         }
  58.     }
  59. }

May 25, 2011

Comments

Aanund Austrheim
Aanund Austrheim May 26, 2011 01:40 AM

I had a slightly different take on the same problem posted (finally) at (http://www.austrheim.org/post/2011/05/26/A-new-PageList.aspx ), but I really like your version better :)

Anders Hattestad
Anders Hattestad May 26, 2011 07:33 AM

Your code solves a problem I'm been trying to work around for some time.
Thanks for sharing. Like your version also. Guess they can exists together :)

My orginal problem is that I have different prosjects so I cant have all the "handlers" in the same prosject.

Kjetil Simensen
Kjetil Simensen May 26, 2011 08:13 AM

Nice solution :)

Another way to get this result can be something like this:

Implement an OnItemCreated on a control that inherits from PageList control, and then have a MultiView inside the itemtemplate and where the views have names that equals the pagetype name. So on item created you just check the container pagetypename and use this to set active view. Inside each view you can have usercontrols or just html, which renders the given pagetype the way you want it.

Anders Hattestad
Anders Hattestad May 26, 2011 08:16 AM

I know, but I needed to have a special view when the IsEventType was checked, or as I also do is to create a dummy pagedata object and have an inner object I need to handle in a special way

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