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.
- public class FormatListAttribute : PlugInAttribute
- {
- public string Url { get; set; }
- public string Key { get; set; }
- public Type[] TriggerOnPageTypes { get; set; }
- public Type[] TriggerOnInnerObject { get; set; }
- public string TriggerOnPropertyIsNotNull { get; set; }
- }
These handlers can be a simple user control as this:
- [FormatList(DisplayName = "ContainerPageType", SortIndex = 100,
- TriggerOnPageTypes = new Type[] { typeof(ContainerPageType) },
- Url = "/Custom/Units/ListViews/ListFormats/ContainerView.ascx")]
- public partial class ContainerView : FormatBaseUserControl
- {
- protected void Page_Load(object sender, EventArgs e) { }
- public override void DataBind()
- {
- Childs.DataSource = EPiServer.DataFactory.Instance.GetChildren(CurrentPage.PageLink);
- Childs.DataBind();
- base.DataBind();
- }
- }
- <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ContainerView.ascx.cs" Inherits="UDFase1.Custom.Units.ListViews.ListFormats.ContainerView" %>
- <Itera:Property ID="Property12" runat="server"PropertyName="PageLink"
- AddFirst="<h2>" AddLast="</h2>" />
- <Itera:Property ID="Property2" runat="server" PropertyName="MainIntro|MainBody:StripHtml(200)" AddFirst="<p>" AddLast="</p>" />
- <EPiServer:PageList ID="Childs" runat="server" MaxCount="7" EnableVisibleInMenu=true>
- <ItemTemplate><Itera:Property ID="Property12" runat="server" PropertyName="PageLink" AddFirst="<nobr>[" AddLast="]</nobr>" /> </ItemTemplate>
- </EPiServer:PageList>
This user control will display one page of ContainerPageType with an header, and all its child elements bellow.Like this:
while other items can have there own handler.
So its possible to get lists like this:
where each “row” is handled by a separate handler.
How
I made myself a web control that inherits from PageList
- public class PageListFormat : PageList
- {
- public string FormatMustContainKey { get; set; }
- public Dictionary<PageData, object> InnerObjects { get; set; }
- public Dictionary<PageData, object> ExtraDisplayInfo { get; set; }
- public bool ShowDebug { get; set; }
- protected override void CreateChildControls()
- {
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
- var plugins2 = EPiServer.PlugIn.PlugInLocator.FindPlugInTypes(typeof(FormatListAttribute));
- var plugins = new List<PlugInDescriptor>();
- foreach (var i in plugins2)
- if (string.IsNullOrEmpty(FormatMustContainKey))
- {
- plugins.Add(i);
- }
- else
- {
- FormatListAttribute att = i.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
- if (!string.IsNullOrEmpty(att.Key) && att.Key.Contains(FormatMustContainKey))
- plugins.Add(i);
- }
- plugins.Sort(SortPlugInDescriptor);
Then its just a question of what handler to use for a given page.
- FormatListAttribute GetHandler(PageData page, List<PlugInDescriptor> plugins, StringBuilder debug, Control control2)
- {
- debug.Append("<br />Checking page " + page.PageName);
- foreach (var p in plugins)
- {
- FormatListAttribute att = p.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
- if (InnerObjects != null && att.TriggerOnInnerObject != null && InnerObjects.ContainsKey(page))
- {
- var check = InnerObjects[page];
- debug.Append("<br />Check inner objects" + check);
- foreach (var t in att.TriggerOnInnerObject)
- if (t.IsInstanceOfType(check))
- return att;
- }
- if (att.TriggerOnPageTypes != null)
- {
- debug.Append("<br />Check page type");
- foreach (var t in att.TriggerOnPageTypes)
- if (t.IsInstanceOfType(page))
- return att;
- }
- if (!string.IsNullOrEmpty(att.TriggerOnPropertyIsNotNull) && page.Property[att.TriggerOnPropertyIsNotNull] != null && !page.Property[att.TriggerOnPropertyIsNotNull].IsNull)
- {
- debug.Append("<br />TriggerOnPropertyIsNotNull");
- return att;
- }
- }
- return null;
- }
so if I make a handler for an event
- [FormatList(DisplayName = "EventView", SortIndex = 20,
- TriggerOnPropertyIsNotNull = "IsTypeEvent",
- Url = "/Custom/Units/ListViews/ListFormats/EventView.ascx")]
- public partial class EventView : FormatBaseUserControl
- {
all pages with IsTypeEvent checked will be displayed accordingly to the front end code, for instance like this
The PageList control can look like this
- <Itera:PageListFormat id="PageListFormat1" runat="server">
- <StartTemplate><div></StartTemplate>
- <EndTemplate></div></EndTemplate>
- <ItemTemplate>
- <div>Not handled</div>
- </ItemTemplate>
- </Itera:PageListFormat>
to load another ITemplate using code is very easy, just load it like this
- 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
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using EPiServer.Web.WebControls;
- using EPiServer.Core;
- using System.Web.UI;
- using EPiServer.PlugIn;
- using System.Web.UI.WebControls;
- using Itera.PageListWithFormat;
- using System.ComponentModel;
- using System.Collections;
- namespace Itera.WebControls
- {
- public class PageListFormat : PageList
- {
- public string FormatMustContainKey { get; set; }
- public Dictionary<PageData, object> InnerObjects { get; set; }
- public Dictionary<PageData, object> ExtraDisplayInfo { get; set; }
- public bool ShowDebug { get; set; }
- protected override void CreateChildControls()
- {
- PageDataCollection pages = base.GetPages();
- if (pages.Count == 0)
- {
- return;
- }
- StringBuilder debug = new StringBuilder();
- PageData page = null;
- if (!PageReference.IsNullOrEmpty(this.PageLink))
- {
- page = this.GetPage(this.PageLink);
- }
- if (this.HeaderTemplate != null)
- {
- Control control = new PageTemplateContainer(page);
- this.HeaderTemplate.InstantiateIn(control);
- this.Controls.Add(control);
- }
- this.PreparePagingControls(pages);
- var plugins2 = EPiServer.PlugIn.PlugInLocator.FindPlugInTypes(typeof(FormatListAttribute));
- var plugins = new List<PlugInDescriptor>();
- foreach (var i in plugins2)
- if (string.IsNullOrEmpty(FormatMustContainKey))
- {
- plugins.Add(i);
- }
- else
- {
- FormatListAttribute att = i.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
- if (!string.IsNullOrEmpty(att.Key) && att.Key.Contains(FormatMustContainKey))
- plugins.Add(i);
- }
- plugins.Sort(SortPlugInDescriptor);
- debug.Append("<div style='clear:both;'><table>");
- foreach (var p in plugins)
- {
- FormatListAttribute att = p.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
- debug.Append("<tr><td>" + att.DisplayName + "</td><td>" + att.SortIndex + "</td></tr>");
- }
- debug.Append("</table><ul>");
- for (int i = 0; i < pages.Count; i++)
- {
- Control control2 = CreateTemplateContainer(pages, i);
- debug.Append("<li>Page " + i + " " + pages[i].PageName + " [" + pages[i] + "]");
- CreateTemplate(debug, pages, plugins, i, control2);
- debug.Append("</li>");
- }
- debug.Append("</ul></div>");
- if (this.FooterTemplate != null)
- {
- Control control3 = new FormatTemplateContainer(page);
- this.FooterTemplate.InstantiateIn(control3);
- this.Controls.Add(control3);
- }
- this.CreatePagingControls(pages);
- if (ShowDebug)
- this.Controls.Add(new Literal() { Text = debug.ToString(), ID = "Debug" });
- }
- private Control CreateTemplateContainer(PageDataCollection pages, int i)
- {
- object innerObject = null;
- if (InnerObjects != null && InnerObjects.ContainsKey(pages[i]))
- innerObject = InnerObjects[pages[i]];
- object extraInfo = null;
- if (ExtraDisplayInfo != null && ExtraDisplayInfo.ContainsKey(pages[i]))
- extraInfo = ExtraDisplayInfo[pages[i]];
- Control control2 = new FormatTemplateContainer(pages[i], innerObject, extraInfo);
- return control2;
- }
- private void CreateTemplate(StringBuilder debug, PageDataCollection pages, List<PlugInDescriptor> plugins, int i, Control control2)
- {
- var handler = GetHandler(pages[i], plugins, debug, control2);
- if (handler != null)
- {
- if (StartTemplate != null)
- {
- Control start = new FormatTemplateContainer(pages[i]);
- StartTemplate.InstantiateIn(start);
- this.Controls.Add(start);
- }
- debug.Append("<br />Found handler " + handler.Url);
- var handlerTemplate = this.Page.LoadTemplate(handler.Url);
- if (handlerTemplate is EPiServer.UserControlBase)
- {
- (handlerTemplate as EPiServer.UserControlBase).CurrentPage = pages[i];
- }
- handlerTemplate.InstantiateIn(control2);
- this.Controls.Add(control2);
- if (EndTemplate != null)
- {
- Control end = new FormatTemplateContainer(pages[i]);
- EndTemplate.InstantiateIn(end);
- this.Controls.Add(end);
- }
- }
- else
- {
- debug.Append("<br />using default");
- this.ItemTemplate.InstantiateIn(control2);
- this.Controls.Add(control2);
- }
- }
- FormatListAttribute GetHandler(PageData page, List<PlugInDescriptor> plugins, StringBuilder debug, Control control2)
- {
- debug.Append("<br />Checking page " + page.PageName);
- foreach (var p in plugins)
- {
- FormatListAttribute att = p.GetAttribute(typeof(FormatListAttribute)) as FormatListAttribute;
- if (InnerObjects != null && att.TriggerOnInnerObject != null && InnerObjects.ContainsKey(page))
- {
- var check = InnerObjects[page];
- debug.Append("<br />Check inner objects" + check);
- foreach (var t in att.TriggerOnInnerObject)
- if (t.IsInstanceOfType(check))
- return att;
- }
- if (att.TriggerOnPageTypes != null)
- {
- debug.Append("<br />Check page type");
- foreach (var t in att.TriggerOnPageTypes)
- if (t.IsInstanceOfType(page))
- return att;
- }
- if (!string.IsNullOrEmpty(att.TriggerOnPropertyIsNotNull) && page.Property[att.TriggerOnPropertyIsNotNull] != null && !page.Property[att.TriggerOnPropertyIsNotNull].IsNull)
- {
- debug.Append("<br />TriggerOnPropertyIsNotNull");
- return att;
- }
- }
- return null;
- }
- [PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(FormatTemplateContainer)), Browsable(false)]
- public ITemplate StartTemplate { get; set; }
- [PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(FormatTemplateContainer)), Browsable(false)]
- public ITemplate EndTemplate { get; set; }
- public static int SortPlugInDescriptor(PlugInDescriptor a, PlugInDescriptor b)
- {
- int aN = a.GetAttribute(typeof(FormatListAttribute)).SortIndex;
- int bN = b.GetAttribute(typeof(FormatListAttribute)).SortIndex;
- return aN.CompareTo(bN);
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using EPiServer.PlugIn;
- namespace Itera.PageListWithFormat
- {
- public class FormatListAttribute : PlugInAttribute
- {
- public string Url { get; set; }
- public string Key { get; set; }
- public Type[] TriggerOnPageTypes { get; set; }
- public Type[] TriggerOnInnerObject { get; set; }
- public string TriggerOnPropertyIsNotNull { get; set; }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using EPiServer.Web.WebControls;
- using EPiServer.Core;
- using System.Web.UI;
- namespace Itera.PageListWithFormat
- {
- public class FormatTemplateContainer : PageTemplateContainer
- {
- public FormatTemplateContainer(PageData page)
- : base(page)
- {
- }
- public FormatTemplateContainer(PageData page, object innerObject, object extraDisplay)
- : base(page)
- {
- InnerObject = innerObject;
- ExtraDisplayInfo = extraDisplay;
- }
- public object InnerObject { get; set; }
- public object ExtraDisplayInfo { get; set; }
- }
- public class FormatBaseUserControl : EPiServer.UserControlBase
- {
- public new PageData CurrentPage
- {
- get
- {
- if (this.Parent is FormatTemplateContainer)
- return (this.Parent as FormatTemplateContainer).CurrentPage;
- return null;
- }
- }
- public object InnerObject
- {
- get
- {
- if (this.Parent is FormatTemplateContainer)
- return (this.Parent as FormatTemplateContainer).InnerObject;
- return null;
- }
- }
- public object ExtraDisplayInfo
- {
- get
- {
- if (this.Parent is FormatTemplateContainer)
- return (this.Parent as FormatTemplateContainer).ExtraDisplayInfo;
- return null;
- }
- }
- }
- }
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 :)
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.
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.
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