It is so common to use class name for markup, but you can assign another name if you want, I do not explain more, if you want please comment
when asp.net compiles markup, it uses default parameter less constructor
you can use any collection type but if you want to use benefits of viewstate your collection type must implement IStateManager interface (below I wrote source of collection that I created for my self with state managing support)
Yes, your control can have multiple collections, just add required attributes as below:
(I used one of my codes, please replace names with your desired name)
if you want to have collection first of all you must define its property in your control.
imagine we have a control named CustomControl that extends Control as below:
[System.Web.UI.ParseChildrenAttribute(true)]
[System.Web.UI.PersistChildrenAttribute(false)]
public class CustomControl : Control{
private GraphCollection m_graphs;
[Bindable(false)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public GraphCollection Graphs
{
get
{
if (this.m_graphs == null) {
this.m_graphs = new GraphCollection();
if (base.IsTrackingViewState) {
this.m_graphs.TrackViewState();
}
}
return this.m_graphs;
}
}
}
as you can see in above code, CustomControl has a field with name "m_graphs" with type of "GraphCollection", also a property that exposes this field
also please please pay attention to its attribute PersistenceMode that says to asp.net property "Graphs" must persisted as InnerProperty
also please pay attention to two attributes applied to CustomControl class
attribute ParseChildrenAttribute says to asp.net that nested markup, must be treated as properties and attribute PersistChildrenAttribute says to asp.net that nested markups are not control's children
at the final, I bring two source codes for state managing components
first of all GraphCollection that extends from StateManagedCollection (both classes was written by me)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
namespace Farayan.Web.Core
{
public class StateManagedCollection<T> : IList, ICollection, IEnumerable, IEnumerable<T>, IStateManager
where T : class, IStateManager, new()
{
// Fields
private List<T> listItems = new List<T>();
private bool marked = false;
private bool saveAll = false;
// Methods
public void Add(T item)
{
this.listItems.Add(item);
if (this.marked) {
//item.Dirty = true;
}
}
public void AddRange(T[] items)
{
if (items == null) {
throw new ArgumentNullException("items");
}
foreach (T item in items) {
this.Add(item);
}
}
public void Clear()
{
this.listItems.Clear();
if (this.marked) {
this.saveAll = true;
}
}
public bool Contains(T item)
{
return this.listItems.Contains(item);
}
public void CopyTo(Array array, int index)
{
this.listItems.CopyTo(array.Cast<T>().ToArray(), index);
}
public IEnumerator GetEnumerator()
{
return this.listItems.GetEnumerator();
}
public int IndexOf(T item)
{
return this.listItems.IndexOf(item);
}
public void Insert(int index, T item)
{
this.listItems.Insert(index, item);
if (this.marked) {
this.saveAll = true;
}
}
public void LoadViewState(object state)
{
object[] states = state as object[];
if (state == null || states.Length == 0)
return;
for (int i = 0; i < states.Length; i++) {
object itemState = states[i];
if (i < Count) {
T day = (T)listItems[i];
((IStateManager)day).LoadViewState(itemState);
} else {
T day = new T();
((IStateManager)day).LoadViewState(itemState);
listItems.Add(day);
}
}
}
public void Remove(T item)
{
int index = this.IndexOf(item);
if (index >= 0)
this.RemoveAt(index);
}
public void RemoveAt(int index)
{
this.listItems.RemoveAt(index);
if (this.marked) {
this.saveAll = true;
}
}
public object SaveViewState()
{
List<object> state = new List<object>(Count);
foreach (T day in listItems)
state.Add(((IStateManager)day).SaveViewState());
return state.ToArray();
}
int IList.Add(object item)
{
T item2 = (T)item;
this.listItems.Add(item2);
return listItems.Count - 1;
}
bool IList.Contains(object item)
{
return this.Contains((T)item);
}
int IList.IndexOf(object item)
{
return this.IndexOf((T)item);
}
void IList.Insert(int index, object item)
{
this.Insert(index, (T)item);
}
void IList.Remove(object item)
{
this.Remove((T)item);
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
public void TrackViewState()
{
this.marked = true;
for (int i = 0; i < this.Count; i++) {
((IStateManager)this[i]).TrackViewState();
}
}
// Properties
public int Capacity
{
get
{
return this.listItems.Capacity;
}
set
{
this.listItems.Capacity = value;
}
}
public int Count
{
get
{
return this.listItems.Count;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public T this[int index]
{
get
{
return (T)this.listItems[index];
}
}
public object SyncRoot
{
get
{
return this;
}
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
object IList.this[int index]
{
get
{
return this.listItems[index];
}
set
{
this.listItems[index] = (T)value;
}
}
bool IStateManager.IsTrackingViewState
{
get
{
return this.marked;
}
}
#region IEnumerable<T> Members
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return this.listItems.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}
and GraphCollection
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Farayan.Web.Core;
namespace Farayan.Web.AmCharts
{
public class GraphCollection : StateManagedCollection<Graph>
{
}
}
and finally Graph in our example:
using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Web.UI;
using System.ComponentModel;
using Farayan.Web.AmCharts;
using System.Collections.Generic;
using Farayan.Web.Controls;
using System.Runtime;
using Farayan.Web.Core;
namespace Farayan.Web.AmCharts
{
public class Graph : StateManager
{
#region Colorize Property
[Browsable(true)]
[Localizable(false)]
[PersistenceMode(PersistenceMode.Attribute)]
[DefaultValue(false)]
public virtual bool Colorize
{
get { return ViewState["Colorize"] == null ? false : (bool)ViewState["Colorize"]; }
set { ViewState["Colorize"] = value; }
}
#endregion
//==============================
public override void LoadViewState(object state)
{
base.LoadViewState(state);
}
public override object SaveViewState()
{
return base.SaveViewState();
}
}
}
you may noticed that Graph extends StateManager class
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Web.UI;
using Farayan.Web.AmCharts;
namespace Farayan.Web.AmCharts
{
public class StateManager : IStateManager
{
protected StateBag ViewState = new StateBag();
#region IStateManager Members
public virtual bool IsTrackingViewState
{
get { return true; }
}
public virtual void LoadViewState(object state)
{
if (state != null) {
ArrayList arrayList = (ArrayList)state;
for (int i = 0; i < arrayList.Count; i += 2) {
string value = ((IndexedString)arrayList[i]).Value;
object value2 = arrayList[i + 1];
ViewState.Add(value, value2);
}
}
}
public virtual object SaveViewState()
{
ArrayList arrayList = new ArrayList();
if (this.ViewState.Count != 0) {
IDictionaryEnumerator enumerator = this.ViewState.GetEnumerator();
while (enumerator.MoveNext()) {
StateItem stateItem = (StateItem)enumerator.Value;
//if (stateItem.IsDirty) {
if (arrayList == null) {
arrayList = new ArrayList();
}
arrayList.Add(new IndexedString((string)enumerator.Key));
arrayList.Add(stateItem.Value);
//}
}
}
return arrayList;
}
public virtual void TrackViewState()
{
}
#endregion
#region IStateManager Members
bool IStateManager.IsTrackingViewState
{
get { return this.IsTrackingViewState; }
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
#endregion
}
}