在ASP.NET开发过程中,ViewState是一个常见的问题,因为它通常占用了大量内存。尽管可以通过禁用特定控件或整个页面的ViewState来减小其大小,但这样可能会导致失去一些高级功能,如选择项目或分页。本文将介绍如何优化DataGrid控件的ViewState,同时保持其所有功能。
当开始学习和实践使用ASP.NET时,ViewState是一个让头疼的问题。通常,ViewState的大小过大,可以通过禁用特定控件或整个页面的ViewState来减小其大小。不幸的是,禁用ViewState后,有时会失去一些功能。对于DataGrid来说尤其如此,禁用ViewState后,将失去选择项目或分页等高级功能。另一方面,DataGrid生成的ViewState通常非常大,并且随着每行每列的添加而增长。
在过去的两周里,决定解决这个问题。假设DataGrid在ViewState中存储了DataTable的副本,或者数据是按列存储的BoundColumn对象。但后来发现这是一个错误的假设。
首先,展示了用于显示页面的整个控件树。第一个惊喜是DataGrid内部使用了其他控件来显示其内容。下面是一个2x2 DataGrid的示例控件树:
DataGrid
DataGridTable
DataGridItem
TableCell
TableCell
DataGridItem
TableCell
TableCell
DataGridTable类是从System.Web.UI.WebControls.Table派生的。DataGridItem对象表示行,TableCell表示DataGrid的单元格。
接下来,使用反射工具(Reflector)反编译.NET二进制文件,并浏览了DataGrid、BaseDataList(其基类)、BoundColumn和DataGridColumn类的代码。不幸的是,没有找到可以帮助解决问题的内容。
在这一点上,决定尝试解码并分析ViewState的内容。使用了ViewState Decoder工具来完成这项工作。当显示ViewState的数据时,其结构对来说很熟悉。之后,发现它类似于页面上的控件树。想,如果禁用DataGrid每行的ViewState会怎样?检查了这个方法,结果发现...就是它!
以下是减小DataGridViewState大小的一些方法:
C#
private void DisableViewState(DataGrid dg)
{
foreach (DataGridItem dgi in dg.Items)
{
dgi.EnableViewState = false;
}
}
private void Page_Load(object sender, System.EventArgs e)
{
MyDataGrid.DataSource = GetData();
MyDataGrid.DataBind();
DisableViewState(MyDataGrid);
}
例如:有一个包含三个ID的数组:1、2、3。如果将它们存储在ViewState中作为string[],将得到:
@<1;2;3;>
如果将它们存储为int[],将得到:
@System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;i<2>;i<3>;>
如果在ViewState中存储更多的int[]数组,除了第一个之外的所有数组都将以以下方式存储:
@50;i<2>;i<3>;>
或者,可以将ID存储在ArrayList中。以下是从ArrayList生成的数据,存储为string和int:
l<1;2;3;>
l;i<2>;i<3>;>
以下是创建并存储ID数组在ViewState中的示例代码:
C#
DataTable dt = GetData();
MyDataGrid.DataSource = dt;
MyDataGrid.DataBind();
string[] ids = new string[dt.Rows.Count];
for (int n = 0; n < dt.Rows.Count; ++n)
ids[n] = dt.Rows[n]["id"].ToString();
ViewState["ids"] = ids;
当需要检索显示数据的ID时,请使用以下代码:
C#
int index = MyDataGrid.SelectedIndex;
string[] ids = (string[])ViewState["ids"];
int myID = Convert.ToInt32(ids[index]);
创建了一个页面,显示了一个10x10的表格。每个单元格包含一个三位数。以下是测试结果:
ViewState大小 | 描述 |
---|---|
6032 | VS启用,CA启用 |
5028 | VS启用,CA禁用 |
236 | VS为行禁用,CA禁用 |
948 | VS为所有列的单元格禁用(除了第一列),CA禁用 |
476 | VS为行禁用,CA禁用,ID以int[]存储在VS中 |
316 | VS为行禁用,CA禁用,ID以string[]存储在VS中 |
356 | VS为行禁用,CA禁用,ID以int存储在VS中的ArrayList中 |
316 | VS为行禁用,CA禁用,ID以string存储在VS中的ArrayList中 |
如所见,ViewState的大小从6032字节减少到316字节。节省了5716字节,现在ViewState仅包含初始数据的5.2%!
花了将近两周的时间来研究本文中介绍的主要方法(禁用DataGrid每行的ViewState)。确实,最简单的解决方案往往是最难找到的。