///
   /// A templated databound repeater that dynamically determines which
   /// template to use based on the class of the object in the collection.
   ///
   [ParseChildren(false)]
   [ControlBuilder(typeof(ObjectRepeaterControlBuilder))]
   public class ObjectRepeater : System.Web.UI.Control, System.Web.UI.INamingContainer, IParserAccessor
   {
      private Hashtable _templates = new Hashtable();
      private string _defaultTemplateName = null;
      private IEnumerable _dataSource;
Â
      public ObjectRepeaterDetermineTemplateDelegate DetermineTemplate;
      public event RepeaterItemEventHandler ItemCreated;
      public event RepeaterItemEventHandler ItemDataBound;
      public event RepeaterCommandEventHandler ItemCommand;
Â
      #region Properties
Â
      public string DefaultTemplate
      {
         get
         {
            return _defaultTemplateName;
         }
         set
         {
            _defaultTemplateName = value;
         }
      }
Â
      public virtual IEnumerable DataSource
      {
         get
         {
            return _dataSource;
         }
         set
         {
            _dataSource = value;
         }
      }
Â
      public ControlCollection Items
      {
         get
         {
            return this.Controls;
         }
      }
Â
      #endregion
Â
      #region Methods
Â
      public void OnItemDataBound(RepeaterItemEventArgs e)
      {
         if(this.ItemDataBound != null)
            this.ItemDataBound(this, e);
      }
Â
      public void OnItemCreated(RepeaterItemEventArgs e)
      {
         if(this.ItemCreated != null)
            this.ItemCreated(this, e);
      }
Â
      public void OnItemCommand(RepeaterCommandEventArgs e)
      {
         if(this.ItemCommand != null)
            this.ItemCommand(this, e);
      }
Â
      public override void DataBind()
      {
         // Controls with a data-source property perform their
         // custom data binding by overriding DataBind to
         // evaluate any data-binding expressions on the control  Â
         // itself.
         base.OnDataBinding(EventArgs.Empty);
Â
         // Reset the control's state.
         Controls.Clear();
         ClearChildViewState();
Â
         // Create the control hierarchy using the data source.
         CreateControlHierarchy(true);
         ChildControlsCreated = true;
Â
         TrackViewState();
Â
      }
Â
      protected override void CreateChildControls()
      {
         Controls.Clear();
Â
         if (ViewState["ItemCount"] != null)
         {
            // Create the control hierarchy using the view state,
            // not the data source.
            CreateControlHierarchy(false);
         }
      }
Â
      ///
      ///
      ///
      /// True to create the hierarchy from the DataSource, False to create it from the ViewState.
      private void CreateControlHierarchy(bool useDataSource)
      {
         IEnumerable dataSource = null;
         int count = -1;
Â
         if (useDataSource == false)
         {
            // ViewState must have a non-null value for ItemCount because this is checked
            // by CreateChildControls.
            count = (int)ViewState["ItemCount"];
            if (count != -1)
            {
               dataSource = new DummyDataSource(count);
            }
         }
         else
         {
            dataSource = this._dataSource;
         }
Â
         if (dataSource != null)
         {
            int index = 0;
            count = 0;
            foreach (object dataItem in dataSource)
            {
               CreateItem(index, ListItemType.Item, useDataSource, dataItem);
Â
               count++;
               index++;
            }
         }
Â
         if (useDataSource)
         {
            // Save the number of items contained for use in round trips.
            ViewState["ItemCount"] = ((dataSource != null) ? count : -1);
         }
      }
Â
      private RepeaterItem CreateItem(int itemIndex, ListItemType itemType, bool dataBind, object dataItem)
      {
         RepeaterItem item = new RepeaterItem(itemIndex, itemType);
Â
         RepeaterItemEventArgs e = new RepeaterItemEventArgs(item);
Â
         //decide which template to use.
         string templateName = null;
Â
         if(dataBind)
         {
            if(DetermineTemplate != null)
            {
               templateName = this.DetermineTemplate(this, dataItem);
               ViewState["templateName" + itemIndex.ToString()] = templateName;
            }
         }
         else
         {
            //determine template to use from viewState;
            templateName = (string)ViewState["templateName" + itemIndex.ToString()];
         }
Â
         if(templateName == null)
            templateName = this.DefaultTemplate;
         ObjectTemplate dynamicTemplate = (ObjectTemplate)_templates[templateName];
Â
Â
         //Must exist.
         dynamicTemplate.ItemTemplate.InstantiateIn(item);
Â
         if (dataBind)
         {
            item.DataItem = dataItem;
         }
         OnItemCreated(e);
         this.Controls.Add(item);
Â
         if (dataBind)
         {
            item.DataBind();
            OnItemDataBound(e);
Â
            item.DataItem = null;
         }
Â
         return item;
      }
Â
      protected override bool OnBubbleEvent(object source, EventArgs e)
      {
         // Handle events raised by children by overriding OnBubbleEvent.
Â
         bool handled = false;
Â
         if (e is CommandEventArgs)
         {
            RepeaterCommandEventArgs ce = (RepeaterCommandEventArgs)e;
Â
            OnItemCommand(ce);
            handled = true;
         }
Â
         return handled;
      }
Â
Â
      ///
      /// This member overrides Control.AddParsedSubObject.
      /// it catches the contents of each item.
      ///
      protected override void AddParsedSubObject(object obj)
      {
         if(obj is ObjectTemplate)
         {  Â
            ObjectTemplate template = (ObjectTemplate)obj;
            _templates.Add(template.Name, template);
            return;
         }
         else
         {
            if(!(obj is LiteralControl))
               throw new Exception("ObjectRepeater can only have children of type 'ObjectTemplate'");
         }
         base.AddParsedSubObject(obj);
      }  Â
Â
      #endregion
   }  Â
Â
   public delegate string ObjectRepeaterDetermineTemplateDelegate(object sender, object dataItem);
Â
   #region Control Builder
   ///
   /// Interacts with the parser to build a PanelBar control.
   ///
   public class ObjectRepeaterControlBuilder : ControlBuilder
   {
      ///
      /// This member overrides ControlBuilder.GetChildControlType.
      ///
      public override Type GetChildControlType(string tagName, IDictionary attributes)
      {
         // check is the tag is an TabStripPanelItem tag
         if (tagName.ToLower().IndexOf("objecttemplate") >= 0)
         {
            System.Diagnostics.Trace.WriteLine(tagName);
Â
            // yes, so return TabStripPanelItem type
            return typeof(ObjectTemplate);
Â
         }
         return null;
      }
Â
      public override void AppendLiteralString(string s)
      {
         //empty implementation to drop literal content.
         System.Diagnostics.Trace.WriteLine(s);
      }
Â
   }
   #endregion
Â
   [ParseChildren(true)]
   public class ObjectTemplate : Control
   {
      private string _name;
      private ITemplate _itemTemplate;
Â
      [TemplateContainer(typeof(RepeaterItem))]
      public ITemplate ItemTemplate
      {
         get { return _itemTemplate; }
         set { _itemTemplate = value; }
      }
Â
      public string Name
      {
         get { return _name; }
         set { _name = value; }
      }
   }
   internal sealed class DummyDataSource : ICollection
   {
      private int dataItemCount;
      public DummyDataSource(int dataItemCount)
      {
         this.dataItemCount = dataItemCount;
      }
      public int Count
      {
         get
         {
            return dataItemCount;
         }
      }
      public bool IsReadOnly
      {
         get
         {
            return false;
         }
      }
      public bool IsSynchronized
      {
         get
         {
            return false;
         }
      }
      public object SyncRoot
      {
         get
         {
            return this;
         }
      }
      public void CopyTo(Array array, int index)
      {
         for (IEnumerator e = this.GetEnumerator(); e.MoveNext();)
            array.SetValue(e.Current, index++);
      }
      public IEnumerator GetEnumerator()
      {
         return new BasicDataSourceEnumerator(dataItemCount);
      }
Â
      private class BasicDataSourceEnumerator : IEnumerator
      {
         private int count;
         private int index;
         public BasicDataSourceEnumerator(int count)
         {
            this.count = count;
            this.index = -1;
         }
         public object Current
         {
            get
            {
               return null;
            }
         }
         public bool MoveNext()
         {
            index++;
            return index < count;
         }
         public void Reset()
         {
            this.index = -1;
         }
      }
   }