Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DataGrid's ViewState optimization

0.00/5 (No votes)
11 Apr 2005 4  
How to reduce DataGrid's ViewState size, while maintaining all DataGrid's functionalities.

Introduction

This article shows you how to reduce size of ViewState data generated by DataGrid control, while maintaining all DataGrid's functionality like selecting items or paging.

I assume that you know what it's and how to use ViewState. If not, please first learn about them, e.g. read article Taking a Bite Out of ASP.NET ViewState. In that article you also find general information about reducing size of ViewState.

Background

When I started to learn and use ASP.NET in practice, one of my problems was ViewState - usually it's too large! Usually I can reduce its size, by disabling it for selected controls or for whole page. Unfortunately, when I disable VS for control, sometime I lost some of its functionality. This is true for DataGrid - when you disable ViewState, you'll lose advanced functions like selecting items or paging. On the other side, ViewState generated by DataGrid is usually very large - it grows with every added row and column.

In last two weeks I decided to finally solve this problem. I assumed that DataGrid store copy of my DataTable in ViewState, or my data is stored column-by-column by BoundColumn objects. As I found later, it was a wrong assumption.

First I displayed the whole tree of controls used to display my page. First surprise - DataGrid uses internally other controls to display is contents. Here is sample control tree for 2x2 DataGrid:

  • DataGrid
    • DataGridTable
      • DataGridItem
        • TableCell
        • TableCell
      • DataGridItem
        • TableCell
        • TableCell

DataGridTable is the class derived from System.Web.UI.WebControls.Table. DataGridItem objects represents rows, and TableCell represents cells of DataGrid.

Next I decompiled .NET binaries using Reflector [^] and I browsed code of DataGrid, BaseDataList (its base class), BoundColumn, and DataGridColumn classes. Unfortunately I found nothing that may help me solve my problem.

In this point, I decided to try to decode and analyze contents of my ViewState. I used ViewState Decoder [^] for this. When I displayed my ViewState's data, its structure looked familiar for me. After wards, I found that - it's similar to control tree on my page! And I think - what if I disable ViewState for each row of DataGrid? I checked this and... Eureka! That's it!

How to reduce size of DataGrid's ViewState - summary

Disable ViewState

If you can, disable the ViewState for whole DataGrid (set property EnableViewState to false), or better for whole page. If you need advanced DataGrid's functionality like selecting items or paging, you can't use this method. In this case you should use methods listed below.

Disable columns autogeneration

Set property AutoGenerateColumns to false, and create columns manually using Property Builder for DataGrid control. When columns are generated automatically, information about them is stored in the ViewState.

Disable ViewState for each DataGrid's row

This is the best method, because copy of displayed data is stored in ViewState as values of TableCell.Text property. When you disable that, DataGrid ViewState's size will be constant and don't increase when you display more rows. You can use the following code for this:

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);
}

Store required identifiers in ViewState as string[] array

When you display data for user, you need to store identifiers of displayed data. You can store them in hidden DataGrid's column, but this is not optimal - your ids will be stored as DataGridItem/TableCell/string tree (you also need to change code from previous method to disable ViewState only for selected columns). Better solution is to store ids in ViewState as string[] array. Note: int[] array may seem to be more appropriate, but not: data generated by LosFormatter class is more compact for string[] array than for int[] array. This is caused by fact that class LosFormatter is optimized only for string[] arrays.

Example: You have array of three ids: 1, 2, 3. If you store them in ViewState as string[], you get:

@<1;2;3;>

When you store them as int[], you get:

@System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, 
                  PublicKeyToken=b77a5c561934e089<i<1>;i<2>;i<3>;>

If you store more int[] arrays in ViewState, all except first will be stored as following:

@50<i<1>;i<2>;i<3>;>

Alternatively you can store your ids in ArrayList - below are data generated from ArrayList for values stored as string, and as int:

l<1;2;3;>
l<i<1>;i<2>;i<3>;>

Here is an example code that creates and stores array with ids in ViewState:

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;

When you need to retrieve id of displayed data, use following code:

int index = MyDataGrid.SelectedIndex;
string[] ids = (string[])ViewState["ids"];
int myID = Convert.ToInt32(ids[index]);

Statistics

I created page that display a 10*10 table. Each cell contains a three digit number. Below are results of my tests:

VS - ViewState, CA - columns autogeneration.

Description ViewState size
VS enabled, CA enabled 6032
VS enabled, CA disabled 5028
VS disabled for rows, CA disabled 236
VS disabled for cells in all column except first, CA disabled 948
VS disabled for rows, CA disabled, ids stored in VS as int[] 476
VS disabled for rows, CA disabled, ids stored in VS as string[] 316
VS disabled for rows, CA disabled, ids stored in VS as ints in ArrayList 356
VS disabled for rows, CA disabled, ids stored in VS as strings in ArrayList 316

As you see ViewState, size is reduced from 6032 to 316 bytes. We saved 5716 bytes, and now ViewState contains only 5.2% of the beginning data!

Points of Interest

I worked on primary method covered in this article (disable ViewState for each DataGrid's row) for almost two weeks. It's true that simplest solutions are most difficult to find.

I found also that, data stored in ViewState could be optimized. This can be done if you know how LosFormatter works. Other method is to implement own class to replace LosFormatter and this is the subject for other article.

History

  • 4/11/2005

    First version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here