比如向页面动态添加控件
为什么一定要先加入父控件的controls集合,才能保存初始状态不在回发的时候丢失?
比如:
CheckBoxList chk = new CheckBoxList(); 
form1.Controls.Add(chk); //A
if (!IsPostBack) //B

chk.Items.Add("Hello"); 

A放到B后面就出问题了,不理解?
树上说是调用了TrackViewState()方法

解决方案 »

  1.   

    http://www.cnblogs.com/shcity/articles/1223421.html
    http://www.cnblogs.com/jincwfly/archive/2007/03/19/680088.html
      

  2.   

    是要这样, 要保证启用视图状态. 你上面的.Controls.Add方法实际上是System.Web.UI.Control基类提供的,
    在Add方法中有启用控件视图状态的代码.   6.7  对动态添加控件的视图状态分析
    这一节讲点与视图状态相关的有趣的东西。我们在开发ASP.NET页面时,有时候在Page_Load事件中动态创建控件,而当页面提交后,动态修改的数据就丢失了。举个例子,看看如下代码:
     protected void Page_Load(object sender, EventArgs e) {     ListBox lb = new ListBox();     if (!Page.IsPostBack)     {         lb.Items.Add("子项1");     }     this.form1.Controls.Add(lb); } 以上代码首先动态创建一个ListBox控件lb,在页面第一次请求时(提交后不再执行此句)为它增加一个集合项“子项1”,最后把lb添加到当前form集合中。这时如果单击页面中事先放置的“提交”按钮,则页面提交后不再看到“子项1”,也就是说在视图状态中没有存储该item项。为了解决此问题,把代码修改成: 
    protected void Page_Load(object sender, EventArgs e){    ListBox lb = new ListBox();    (lb.Items as IStateManager).TrackViewState();    if (!Page.IsPostBack)    {        lb.Items.Add("子项1");    }    this.form1.Controls.Add(lb);} u  以上代码在为ListBox控件lb增加集合子项时之前,先启用Items属性的视图跟踪监控。这样当页面再提交时,则集合项“子项1”仍然能够呈现。扩展一下,多增加几个Item并设置几个为选中状态,再次提交页面,增加的几个item仍然能够被视图状态成功保存,且能够记住当前是否选中状态。这是为什么呢?原来ListBox控件的属性Items的继承基类ListControl中有个ListItemCollection类型的items对象,像“子项1”这些item就是被增加到items对象中进行管理的。关键的一点是,ListItemCollection集合对象实现了IStateManager接口,看一下它的类定义:/// <summary>/// 获得本书更多内容,请看:/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx/// </summary>public sealed class ListItemCollection : IList, ICollection, IEnumerable, IStateManager{    // Fields    private ArrayList listItems;    private bool ed;    private bool saveAll;     // Methods    public ListItemCollection();    public void Add(string item);    public void Add(ListItem item);    public void AddRange(ListItem[] items);    public void Clear();    public bool Contains(ListItem item);    public void CopyTo(Array array, int index);    public ListItem FindByText(string text);    internal int FindByTextInternal(string text, bool includeDisabled);    public ListItem FindByValue(string value);    internal int FindByValueInternal(string value, bool includeDisabled);    public IEnumerator GetEnumerator();    public int IndexOf(ListItem item);    public void Insert(int index, string item);    public void Insert(int index, ListItem item);    internal void LoadViewState(object state);    public void Remove(string item);    public void Remove(ListItem item);    public void RemoveAt(int index);    internal object SaveViewState();    int IList.Add(object item);    bool IList.Contains(object item);    int IList.IndexOf(object item);    void IList.Insert(int index, object item);    void IList.Remove(object item);    void IStateManager.LoadViewState(object state);    object IStateManager.SaveViewState();    void IStateManager.TrackViewState();    internal void TrackViewState();     // Properties    public int Capacity { get; set; }    public int Count { get; }    public bool IsReadOnly { get; }    public bool IsSynchronized { get; }    public ListItem this[int index] { get; }    public object SyncRoot { get; }    bool IList.IsFixedSize { get; }    object IList.this[int index] { get; set; }    bool IStateManager.IsTrackingViewState { get; }} u  ListItemCollection类实现了IStateManager接口下的几个视图状态相关方法,因为它自身具有视图状态管理能力。基于此,在增加到ListBox对象子项之前,调用这句:(lb.Items as IStateManager).TrackViewState();把它的视图跟踪监控功能打开,即从此刻起视图状态将记录它所有的修改,当然包括它增加的“子项1”项。这就是页面提交“子项1”仍然能够显示在页面上的原因。只有实现了IStateManger接口的集合才能够调用TrackViewState方法打开视图监控。如果没有实现此接口的对象,还有一种方法可以实现视图状态功能,把最初的代码修改成如下格式: protected void Page_Load(object sender, EventArgs e){     ListBox lb = new ListBox();    this.form1.Controls.Add(lb);    if (!Page.IsPostBack)    {        lb.Items.Add("子项1");    }}
     u  在上面的代码中对之前不能够保存视图状态的代码,仅调换了一下代码顺序。把this.form1.Controls.Add(lb)这句放到了lb.Item.Add(“子项1”)之前。运行页面并单击“提交”按钮,就会发现item“子项1”也能够保存视图状态。仅作了代码调整即使lb实现了视图状态保存,这是什么原因呢?这里的关键语句:this.form1.Controls.Add(lb);中的关键方法Add起了重要作用。Controls集合的Add方法最终调用的是Control控件基类中的方法AddedControl。直接看一下AddedControl的代码实现: /// <summary> /// 获得本书更多内容,请看: /// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx /// </summary> protected internal virtual void AddedControl(Control control, int index) {     if (control.OwnerControl != null)     {         throw new InvalidOperationException(SR.GetString("Substitution_          NotAllowed"));     }     if (control._parent != null)     {         control._parent.Controls.Remove(control);     }     control._parent = this;     control._page = this.Page;     control.flags.Clear(0x20000);     Control namingContainer = this.flags[0x80] ? this : this._namingContainer;     if (namingContainer != null)     {         control.UpdateNamingContainer(namingContainer);         if ((control._id == null) && !control.flags[0x40])         {             control.GenerateAutomaticID();         }         else if ((control._id != null) || ((control._occasionalFields != null)          && (control._occasionalFields.Controls != null)))         {             namingContainer.DirtyNameTable();         }     }     if (this._controlState >= ControlState.ChildrenInitialized)     {         control.InitRecursive(namingContainer);         if (((control._controlState >= ControlState.Initialized) && (control.          RareFields != null)) && control.RareFields.RequiredControlState)         {             this.Page.RegisterRequiresControlState(control);         }         if (this._controlState >= ControlState.ViewStateLoaded)         {             object savedState = null;             if ((this._occasionalFields != null) && (this._occasionalFields.              ControlsViewState != null))             {                 savedState = this._occasionalFields.ControlsViewState[index];                 if (this.LoadViewStateByID)                 {                     control.EnsureID();                     savedState =this._occasionalFields.ControlsViewState [control. ID];                     this._occasionalFields.ControlsViewState.Remove (control.ID);                 }                 else                 {                     savedState = this._occasionalFields.ControlsViewState[index];                     this._occasionalFields.ControlsViewState.Remove(index);                 }             }             control.LoadViewStateRecursive(savedState);             if (this._controlState >= ControlState.Loaded)             {                 control.LoadRecursive();                 if (this._controlState >= ControlState.PreRendered)                 {                     control.PreRenderRecursiveInternal();                 }             }         }     } } 
    这是.NET类库代码,不必全部看懂。但要知道此方法能够启用视图状态和向页面请求注册控件状态(假如需要的话)。视图状态跟踪被启用后,接下来执行对item“子项1”的增加当然也能够被页框架视图管理器保存。这里有详细解释:【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—(6)页面状态机制(视图状态和控件状态)】
      http://blog.csdn.net/ChengKing/archive/2009/01/01/3680485.aspx