0

I want to create a custom server control which looks like this:

<cc:MyControl prop1="a" prop2="b">
   <cc:MyItem name="xxx">
   <cc:MyItem name="yyy">
   <cc:MyItem name="zzz">
</cc:MyControl>

MyControl is of course implemented as a server control, however I do not want MyItem to be child controls. Rather they should exist as simple .Net objects. I have a class called MyItem, and the control has a property called Items, and when MyItem elements are declared in the markup, the objects should be instantiated and added to the collection.

The tutorials on MSDN don't actually explain how this happens. See: http://msdn.microsoft.com/en-us/library/9txe1d4x.aspx

I'd like to know:

  1. How is <cc:MyItem> mapped to the MyItem class? Does the element in the markup have to have the same name as the object's class?
  2. Which constructor of MyItem is called when MyItems are added declaratively, and when?
  3. What collection types am I permitted to use to hold MyItem objects? The link above uses ArrayList, but can I use the strongly typed List instead?
  4. Is it possible for a control to contain multiple collections?

1 Answer 1

0
  1. 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

  2. when asp.net compiles markup, it uses default parameter less constructor

  3. 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)

  4. 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
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.