Views: 4285
Number of votes: 0
Average rating:

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

Aanund Austrheim
(By Aanund Austrheim, 5/26/2011 3:40:27 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
(By Anders Hattestad, 5/26/2011 9:33:12 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
(By Kjetil Simensen, 5/26/2011 10:13:52 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
(By Anders Hattestad, 5/26/2011 10:16:50 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.