Control 类

定义由所有 ASP.NET 服务器控件共享的属性、方法和事件。

 

这是在开发自定义 ASP.NET 服务器控件时作为派生源的主要类。Control 没有任何针对用户界面 (UI) 的功能。如果创作没有 UI 的控件或者组合其他呈现它们自己的 UI 的控件,则从 Control 派生。如果创作具有 UI 的控件,则从 WebControl System.Web.UI.WebControls 命名空间中的任何控件派生,该命名空间为自定义控件提供适当的起点。

Control 类是包括自定义控件、用户控件和页在内的所有 ASP.NET 服务器控件的基类。ASP.NET 页是 Page 类(该类从 Control 类继承)的实例,并且处理对扩展名为 .aspx 的文件的请求。

Control 类可以直接或间接地用作 Web 应用程序的用户界面的一部分,因此应对它进行仔细检查,以确保遵循编写安全代码和保护应用程序的最佳做法。

ClientID 属性

void Page_Load(object sender,EventArgs e)
{
       Response.Write("<h4>Control_ClientID Sample</h4>");
       // Get the list of all controls.
      IEnumerator myEnumerator = Controls.GetEnumerator();
      Response.Write("<br />Enumerating Controls Collection<br />");   
      while(myEnumerator.MoveNext())
      {
          Control   myControl = (Control) myEnumerator.Current;
          // Display the ClientID property
          Response.Write("<br />The ClientID property of Control : " + myControl.ClientID);
       }
 }

Controls 属性

获取 ControlCollection 对象,该对象表示 UI 层次结构中指定服务器控件的子控件。

 

Controls.Add(new LiteralControl("<h3>Value: "));

 

 

 

EnableViewState 属性

 

 

 

SaveControlState 方法

 

保存自页回发到服务器后发生的任何服务器控件状态更改。

 

下面的代码示例重写自定义 ASP.NET 控件中的 SaveControlState 方法。调用此方法时,它确定内部属性 currentIndex 是否设置为非默认值,如果是,则将值保存到控件状态。

 

 

 

public class Sample : Control {
    private int currentIndex = 0;

    protected override void OnInit(EventArgs e) {
        Page.RegisterRequiresControlState(this);
        base.OnInit(e);
    }

    protected override object SaveControlState() {
        return currentIndex != 0 ? (object)currentIndex : null;
    }

    protected override void LoadControlState(object state) {
        if (state != null) {
            currentIndex = (int)state;
        }
    }
}

 

 

LoadControlState 方法

 

SaveControlState 方法保存的上一个页请求还原控件状态信息。

TrackViewState 方法

下面是来源于csdn我把它拿来是想理解这个不好理解的属性,对作者表示非常的感谢,使我终于理解了这一个不好理解的属性

让人糊涂的TrackViewState()与视图状态保存

在ASP.NET自定义控件开发中,如果需要自己实现控件的状态保存,一般都要实现SaveViewState(),LoadViewState()和TrackViewState()三个方法,这是由IStateManager接口所定义的。

前两个方法作用很明晰,SaveViewState()是将控件的当前状态抽取为一个状态对象,页面类获取所有控件的状态对象对其进行编码生成可在网络上传输的格式(Base64),并将其塞入到一个id为__VIEWSTATE的input元素中发给浏览器。

 LoadViewState()是控件从浏览器中传回来的数据中重新读取值,使其回复到上次状态。

最头痛的是TrackViewState(),它是干什么的?MSDN里的话如下: 

Causes tracking of view-state changes to the server control so they can be stored in the server control's StateBag object. This object is accessible through the Control.ViewState property.   

这个话无比正确,但却让人不怎么明白。它怎么就让控件跟踪视图状态的变化了?浏览器回发的数据包含了页面当前控件的值,而__VIEWSTATE隐藏域中包含了上次控件的状态,两者一比不就知道哪些变化了,用你TrackViewState()是干什么?

 Google了许多资料,几乎就没发现有价值的介绍,最后,终于在一篇文章《TRULY Understanding ViewState 》中发现了有价值的东西,它的网址如下:   http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx

原来,为了减少在网络上的传输量,应该只保存“变化”的数据到视图状态中。

所有Web控件大都派生自Control类,Control类有一个ViewState属性,它是一个StateBag类的对象。控件可以有多个属性,每个属性都有一个值,StateBag对象按照“Key-Item”格式管理这些数据,一般将属性名当作Key。Item则封装了对应属性的值(注意它是一个StateItem类型的对象)。

StateBag对象保存的Item有一个IsDirty属性用于标识此Item是否有更改。为此,StateBag对象设置了一个标记,当此标记为true时,在给Item赋值时就会同步设置这一Item的IsDirty属性,通告外界——我的数据有变化。而这个内部标记就可以通过TrackView()方法进行设置。如果不设置这个内部标记,那么,不管怎样修改StateBag中的Item,这一Item其IsDirty属性始终都是false。

可以设计一个简单的网页,然后用Reflector查看其生成的程序集源码。

检看StateBag的源码,发现它有以下的代码说明这个内部标记名为marked.
private bool marked;

以下为StateBag的TrackViewState()的反汇编代码:

internal void TrackViewState()
{
    this.marked = true;
}

向ViewState中追加数据的方法本质上是通过StateBag的Add()方法实现的:

public StateItem Add(string key, object value)
{
 //Key不能为空
    if (string.IsNullOrEmpty(key))
    {
        throw ExceptionUtil.ParameterNullOrEmpty("key");
    }
    //根据Key查找集合中的数据对象
    StateItem item = this.bag[key] as StateItem;
    if (item == null)  //没有找到对应的数据对象
    {
        //如果传入的value不为空或要求跟踪,则创建一个对象加入到集合中
        if ((value != null) || this.marked)
        {
            item = new StateItem(value);
            this.bag.Add(key, item);
        }
    }
    else 
     //如果找到对应的数据对象

          if ((value == null) && !this.marked)
          {
              this.bag.Remove(key); //值为空,且不要求跟踪,则从集合中移除此对象
           }
          else  //要求跟踪或者值不为空,设置对应的数据对象值
          {
              item.Value = value;
           }

 //设定已更改标记
    if ((item != null) && this.marked)
    {
        item.IsDirty = true;
    }
    return item;
}


可以清楚地看到,如果标记被设置,IsDirty属性就返回true,否则,保持为false.
注意:这里并没有比对原始值和传入的值是否相等再设置IsDirty属性。因此,只要标记被设置,任何对视图状态的非空赋值都被认为是Dirty的。
 
因此,TrackView()方法其实就是设置了一个“请监控我的变化”的标记,调用此方法之后,任何对控件属性的改变都会被跟踪,这样一来,此控件的SaveViewState()方法在生成状态对象时就会将此属性的修改记录下来。简单地说:只有IsDirty=true的属性值才会被SaveViewState()方法处理。这就避免了为控件所有的属性都生成状态数据,大大减少了要保存的数据量。
以下为StateBag类的SaveViewState()反汇编代码,可以清楚地看到其中使用了IsDirty属性。

internal object SaveViewState()
{
    ArrayList list = null;
    if (this.bag.Count != 0)
    {
        IDictionaryEnumerator enumerator = this.bag.GetEnumerator();
        while (enumerator.MoveNext())
        {
            StateItem item = (StateItem) enumerator.Value;
            if (item.IsDirty)
            {
                if (list == null)
                {
                    list = new ArrayList();
                }
                list.Add(new IndexedString((string) enumerator.Key));
                list.Add(item.Value);
            }
        }
    }
    return list;
}


一切都清楚了。

那么,到底控件的视图状态是怎样保存的?这涉及到页面的生命周期。

当页面被装载时,它的ProcessRequest()方法被调用。在此方法中,会调用一个SaveAllState方法,此方法内部又调用SaveViewStateRecursive()方法(来自基类Control),
SaveViewStateRecursive()先调用Control.SaveViewState()保存自己的数据,再递归地调用每个子控件的SaveViewStateRecursive()方法获取所有子控件的状态对象,然后一级级返回,最终得到整个页面的状态对象,紧接着将这一对象按Base64编码生成页面视图状态字串并放入到__VIEWSTATE隐藏域中(由Page.SavePageStateToPersistenceMedium方法完成)。

综上所述:
如果控件没调用TrackView()方法,那么,本次对控件属性的修改将不会被添加到__VIEWSTATE隐藏域中,因此,下次页面回发时,控件的属性将回复为默认值。
理解这点还是有意义的,特别是在动态创建控件的情况下,请看以下这个典型示例:

 protected void Page_Load(object sender, EventArgs e)
    {
      
        CheckBoxList chk = new CheckBoxList();

        if (!IsPostBack)
        {
            chk.Items.Add("Hello");
        }
        form1.Controls.Add(chk);

    }

 在Page上扔个Button,以便可以PostBack。运行后Postback的结果,“Hello” item没被保留。
改为:

protected void Page_Load(object sender, EventArgs e)
    {
      
        CheckBoxList chk = new CheckBoxList();
        form1.Controls.Add(chk);

        if (!IsPostBack)
        {
            chk.Items.Add("Hello");
        }
      

    }
或者:
 protected void Page_Load(object sender, EventArgs e)
    {
      
        CheckBoxList chk = new CheckBoxList();
        (chk.Items as IStateManager).TrackViewState();
        if (!IsPostBack)
        {
            chk.Items.Add("Hello");
        }
        form1.Controls.Add(chk);

    }
都可以在多次回发时保证Hello项出现,并正确地恢复它的状态(选中还是不选中)。

这个例子说明:将控件加入到页面类的Controls集合中时,会自动调用TrackViewState()方法。

注意:Control.TrackViewState()方法是保护的,不允许外界调用。而动态创建Button等简单控件时,没有办法在页面类中直接调用TrackViewState()方法。因此,通过Controls.Add()方法间接调用TrackViewState()方法是唯一的选择。

最后给出一条动态创建控件的原则:

应该在new出控件对象之后,马上将其加入到父控件的Controls集合中,这样可以完全地保证它的状态能在回发时恢复。

============================
为了弄明白这点小东西,先后看了MSDN无数遍,Google了N篇文章,又用Reflector反汇编,累晕了。

再次感叹,ASP.NET框架内部的机制太复杂太庞大了,有的时候,还真是得“不求甚解”,不然,要弄清楚所有底层技术细节,恐怕胡须都白了。

 

 

导致跟踪服务器控件的视图状态的更改,以便这些更改可以存储到服务器控件的 StateBag 对象中。通过 Control..::.ViewState 属性可访问此对象。

 

 

 

 

 

 

 

 

 

 

SaveViewState 方法

保存自页回发到服务器后发生的任何服务器控件视图状态更改。

 

视图状态是服务器控件属性值的累计。这些值自动放在服务器控件的 ViewState 属性中,该属性是 StateBag 类的实例。然后该属性的值在服务器控件生存期的保存状态阶段后持续到一个字符串对象。有关更多信息,请参见 ASP.NET 页生命周期概述

保存了视图状态后,该字符串对象被作为存储在 HTMLHIDDEN 元素中的变量返回给客户端。使用自定义视图状态创作自定义服务器控件时,可以使用 SaveViewStateLoadViewState 方法显式管理视图状态。有关更多信息,请参见 ASP.NET 状态管理 。有关实现自定义会话状态提供程序的信息,请参见 实现会话状态存储提供程序

 

下面的示例重写自定义 ASP.NET 服务器控件中的 SaveViewState 方法。调用此方法时,它会确定控件是否有任何子控件,以及包含 Page 的对象是不是回发的结果。如果两者都为 true,它会更改 Label Web 服务器控件的 Text 属性,以读取 Custom Control Has Saved State。然后将控件的视图状态保存为名为 allStates 的对象数组。

protected override object SaveViewState()
{  // Change Text Property of Label when this function is invoked.
   if(HasControls() && (Page.IsPostBack))
   {
      ((Label)(Controls[0])).Text = "Custom Control Has Saved State";
   }
   // Save State as a cumulative array of objects.
   object baseState = base.SaveViewState();
   string userText = UserText;
   string passwordText = PasswordText;
   object[] allStates = new object[3];
   allStates[0] = baseState;
   allStates[1] = userText;
   allStates[2] = PasswordText;
   return allStates;
}

 

 

LoadViewState 方法

SaveViewState 方法保存的上一个页请求还原视图状态信息。

你可能感兴趣的:(tr)