ViewState可以用来做什么?  

  这里列举的每一项都是ViewState需要完成的主要工作,我们将根据这些工作来学习ViewState是如何实现这些功能。

  1,以键值对的方式来存控件的值,和Hashtable的结构类似;

  2,跟踪那些ViewState中出现改变的值,以便对这些脏数据(dirty)进行进一步的处理;

  3,通过序列化将ViewState中的值保存在页面的隐藏域(Hidden Field)中(这是默认的持久化方式),并通过反序列化得到对应的ViewState对象以便进行相应的操作;

  4,在页面回传的过程中自动的存储ViewState中的跟踪的值。

下面列举的是ViewState不能用来做什么的列表,这个其实比了解ViewState是用来做什么的还重要。    

  1,自动保存一个类中变量的状态,无论是private, protected还是public的变量;

  2,可以在页面回传的过程中记住所有状态值;

  3,只要有了ViewState那么每次页面请求时重新构造的数据的操作是不必要的了;

  4,ViewState is not responsible for the population of values that are posted such as by TextBox controls (although it does play an important role) ViewState并不存储那些通过Post键值对回传的数据值(如TextBox的TextBox.Text);

虽然ViewState作为一个整体出现在.NET Framework框架中有它的唯一目的,那就是在页面回传的过程中保存状态值,使原本没有“记忆”的Http协议变得有“记忆”起来。但是上面列举的ViewState的四个主要功能之间却没有太多的关联。所以从逻辑上我们可以将其划分开来,各个击破。

 1, ViewState就是用来存储数据的

  如果你曾经使用过HashTable的话,那么你应该明白我的意思了。这里并没有什么高深的理论。ViewState通过String类型的数据作为索引(注意在ViewState中不允许通过整形下表的方式对其中的项进行访问,如:ViewState.Item(0) 的形式是不允许的。)ViewState对应项中的值可以存储任何类型的值,实施上任何类型的值存储到ViewState中都会被装箱为Object类型。以下是几个对ViewState进行赋值的几个例子。

ViewState["Key1"] = 123.45M; // store a decimal value
ViewState["Key2"] = "abc"; // store a string
ViewState["Key3"] = DateTime.Now; // store a DateTime
ViewState["Key1"] = 123.45M; // store a decimal value
ViewState["Key2"] = "abc"; // store a string
ViewState["Key3"] = DateTime.Now; // store a DateTime

实际上ViewState仅仅就是一个定义在System.Web.UI.Control类中的一个保护类型(Protected)的属性名称。由于所有服务器端的控件,用户自定义控件还有页面(Page)类都是继承自System.Web.UI.Control类,所以这些控件都具有这些属性。ViewState的真正类型实际应该是System.Web.UI.StateBag类。严格的说,虽然StateBag类虽然定义在System.Web的命名空间下,实际上StateBag类和ASP.NET并没有严格上的依存关系,它也完全可以System.Collections命名空间下。事实上许多服务器端控件大多数属性值都是利用ViewState来进行数据存储。你可能认为

TextBox.Text属性是按如下形式存储的:
    public string Text 
{
get { return _text; }
set { _text = value; }
}
    public string Text 
{
get { return _text; }
set { _text = value; }
}
但是你必须注意,上面的形式(通过类的私有字段)并不是大多数ASP.NET 服务器控件存储其属性值得方式。这些控件的属性值大多是通过ViewState来进行存储的。通过Reflector查看TextBox.Text属性的源代码你可以看到类似如下的代码:
   public string Text 
{
get { return (string)ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
    public string Text 
{
get { return (string)ViewState["Text"]; }
set { ViewState["Text"] = value; }
}

 为了表示这个观点的重要性,我这里再重申一遍“大多数ASP.NET 服务器控件存储其属性值得方式是通过ViewState的方式存储的,而不是我们通常想象的那样通过类的私有字段来存储。”即便是用于设定服务器控件样式的Style类中的大多数属性值也是通过ViewState来进行存储的。所以在设计自定义的组件时,对于那些需要存储的组件属性值也最好遵循这个方式。这里我还需要着重讲一个问题,在以ViewState为存储方式的情况下,如果实现属性的默认值(default value),我们可能会认为属性值是这样实现的:

   public class MyClass
{
private string _text = "DefauleValue";
public string Text
{
get { return _text; }
set { _text = value; }
}
}
ASP.NET ViewState详解
    public class MyClass
{
private string _text = "DefauleValue";
public string Text
{
get { return _text; }
set { _text = value; }
}
}
ASP.NET ViewState详解

这样如果在对Text的属性没有设置的时候,直接取Text属性,那么我们可以得到默认值"Default Value!"。那么如果我们使用ViewState来存储的时候如何实现默认值呢?如下所示:

public string Text
{
get { return ViewState["Text"] == null ? "Default Value!" : (string)ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
    public string Text
{
get { return ViewState["Text"] == null ? "Default Value!" : (string)ViewState["Text"]; }
set { ViewState["Text"] = value; }
}

就像操作HashTable一样,如果StateBag(ViewState)中没有包含某个键值的项,那么它会返回一个null(在VB.NET中是返回Nothing)。所以我们可以通过判断对应键值的项是否是null来判断某个ViewState项是否被赋值。然后我们通过三目运算符来根据实际情况来返回默认值或者设置的值。并且使用三目运算符实际上这里还出于一个考虑,那么就是在服务器控件中,如果将某个属性值设置为空(null),那么往往代表的意思是使用此属性的默认值。所以第一种实现方法还存在一个问题,那就是如果把某个属性值设置为null,当我们再取这个属性的时候我们将得到null,而不是我们期望的"Default Value!"了,所以对于第一种实现方法还需要对null这个特殊值进行判断才可以完全满足需求。ViewState还可以被用作其他的作用,比如在页面回传过程中保留某些值,比如我们在页面后台代码中常常使用ViewState("Key") = "SomeValue"的方式来存储值,实际上就是使用了Page类的ViewState属性来进行值得存储。同样的我们也可以在控件级别进行ViewState的字定义存储。

 

2. ViewState可以跟踪值的变化

如果你设置一个控件的属性值,那么你会把ViewState中这个属性值对应的数据弄脏(dirty)的。当然数据这个和数据库中的脏数据不同,这里的脏可以理解为“发生变化”的意思。你知道为什么StateBag会存在,而不会被HashTable取代吗?。虽然他们都是通过名值对的方式来存储值,但是StateBag还具有对其中数据更改的跟踪过程(Tracking ability)。是否进行跟踪的开关可以被设置成开或者关,当调用StateBag.TrackViewState()方法后跟踪开关将被开启。只有在跟踪的开关设置为“开”的情况下StateBag中的数据更改才会被跟踪,只要数据出现修改,那么对应StateBag项的数据将会被标记为“脏的”(dirty)。StateBag还提供了检查一个数据项是否是脏数据的方法 -- IsItemDirty(string key)。你也可以在不更改项数据数值的情况下将对应项设置为脏数据,这里需要使用SetItemDirty(string key)方法。为了说明这些,我们看一下以下的例子。这里我们假设当前的StateBag跟踪的开关是处于关闭状态的。

stateBag.IsItemDirty("key"); // returns false
stateBag["key"] = "abc";
stateBag.IsItemDirty("key"); // still returns false 

stateBag["key"] = "def";
stateBag.IsItemDirty("key"); // STILL returns false 

stateBag.TrackViewState();
stateBag.IsItemDirty("key"); // yup still returns false 

stateBag["key"] = "ghi";
stateBag.IsItemDirty("key"); // TRUE! 

stateBag.SetItemDirty("key", false);
stateBag.IsItemDirty("key"); // FALSE!
View Code

相关文章:

  • 2022-01-12
  • 2021-12-02
  • 2022-01-24
  • 2021-11-20
  • 2022-12-23
  • 2021-05-30
猜你喜欢
  • 2021-07-17
  • 2022-12-23
  • 2022-03-08
相关资源
相似解决方案