Click here to Skip to main content
Click here to Skip to main content

DataGrid's ViewState optimization

By , 11 Apr 2005
 

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

About the Author

Daniel Fruzynski
Web Developer
Germany Germany
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberDaniel Cohen Gindi5 Mar '13 - 8:30 
The disable-viewstate-per-row is simple but brilliant. I've been hacking the ViewState for years, and haven't thought of that. It allows me to keep viewstate of LinkButtons in the header for example, to allow sorting (control events do not work without viewstate).
GeneralWhat will be happen the if we write the code in ItemDataBound event of that gridmemberhasan.rounak5 Jun '11 - 21:21 
Thanks a lot..My page contains only one grid with large amount of data. Its working fine in my page..But I have not understand why you have written a extra function for disabling viewstate and called it every time databind happens..If we do the same in the ItemDataBound event of grid will it cause any problem??? For my page I have checked and its working fine..
Questionhurrrry..,data in "GridView" invisible in post back,need the proper code for "viewstate" implementationmembersumans432428 Oct '09 - 21:43 
Hi!
here's it,
I'm using a gridview/datalist(say) in a updatepanel to display the records as search result (as hyperlinks so that clicking it displays the details of the record in another page) form SQL-server DB and it works fine. Now, when i come back to the page with the GV/DL i can't see the data.
I know that I've to use the "viewstate" can anyone give me the proper and complete view state implementation ansd any other tips also
T.Q! nice day.. Roll eyes | :rolleyes: Roll eyes | :rolleyes:
GeneralWhats the use of this when my data is lost on a post backmemberbhat12343 Feb '06 - 23:56 
I did as whatever was said and on post back my data is lost, so whats the use of such a datagrid
GeneralRe: Whats the use of this when my data is lost on a post backmemberfroman11815 Feb '06 - 7:52 
You have to rebind the data on each postback so you have to decide if the extra hit to the database or whatever datasource you are using is worth reducing the size of the viewstate.
GeneralTry to put 2 or more DataGrids with paging enabled!membercupo11 Oct '05 - 12:01 
This may be good solution if you have only one DataGrid on your page but once you add another Datagrid everything is messed up, unless you pull the data again from the server. I tried this with pager and two DataGrids and it doesn't work!
GeneralRe: Try to put 2 or more DataGrids with paging enabled!memberDaniel Fruzynski12 Oct '05 - 7:38 
This is normal behaviour because DataGrids don't store copy of displayed data in its DataView. You must re-DataBind() grids after every postback:
private void ShowGrid1(int nPage)
{
  DataGrid1.CurrentPageIndex = nPage;
  DataGrid1.DataSource = GetData1();
  DataGrid1.DataBind();
  DisableViewState(DataGrid1);
}
 
private void ShowGrid2(int nPage)
{
  DataGrid2.CurrentPageIndex = nPage;
  DataGrid2.DataSource = GetData2();
  DataGrid2.DataBind();
  DisableViewState(DataGrid2);
}
 
private void DataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
  ShowGrid1(e.NewPageIndex);
  ShowGrid2(DataGrid2.CurrentPageIndex);
}
 
private void DataGrid2_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
  ShowGrid1(DataGrid1.CurrentPageIndex);
  ShowGrid2(e.NewPageIndex);
}

GeneralRe: Try to put 2 or more DataGrids with paging enabled!membercupo12 Oct '05 - 12:31 
I know that but that’s not efficient. Imagine having two DataGrids with paging enabled and each displays 25 records per page and about 200+ pages! Now, when you click next page on the first DataGrid, the second one will lose all of its data, unless you bind it again. Again, that’s not efficient having more than one DataGrid.
GeneralRe: Try to put 2 or more DataGrids with paging enabled!memberDaniel Fruzynski13 Oct '05 - 7:34 
Try to use following solutions:
- move ViewState data from hidden field to other place, e.g. Session. Look here: http://www.codeproject.com/aspnet/ServerViewState.asp[^]
- enable CustomPaging in DataGrid, and retrieve only needed rows from database (http://www.codeproject.com/aspnet/Custom_Pageing.asp[^]). You can also store copy of then in Session, and use them after PostBack.
 
Daniel
 
-- modified at 13:36 Thursday 13th October, 2005
GeneralRe: Try to put 2 or more DataGrids with paging enabled!membercupo13 Oct '05 - 13:16 
Using Session for this kind of data is not efficient and is nonsense. Why would I overload the server instead of the client?
GeneralRe: Try to put 2 or more DataGrids with paging enabled!memberDaniel Fruzynski14 Oct '05 - 22:17 
If you want to overload client instead of server... All that I can suggest you is provide custom SavePageStateToPersistenceMedium/LoadPageStateFromPersistenceMedium functions (look into my prev post for link), and compress ViewState sended to client. You can also use custom LosFormatter class that store data in more efficient way (LosFormatter store most of data as plain text, base64-encoded before sending to client).
 
Daniel
GeneralViewstate Optimizationmemberbarani_7624 Jul '05 - 6:11 
Hi,
 
Yes, that was a great article. I have an issue in my applicaton. Datagrids in my page have 10 rows. Each represents a database Table containing empty text boxes and dropdowns(Which are populated with values for corresponding database field for lookup values. In those grid for few dropdowns, items count is less only but for other dropdowns value might be in thousands). Like this I have around 7 grid each representing a table in tabase with empty textboxes and populated drop downs as I said earlier. This Query screen facilitates search kind of functionality. User enters criteria in text boxes or chooses drop down values. Based on the criteria entered by user , the page should build sql dynamically and fethch results and populate in another result grid.It is client requirement
 
This has increased the view state enormously to 4 mb size which is a big performance issue.
 
Since I load all dropdowns in the page load, all the grids adds viewstate content enormously and lead to performance issue.
 
I have made all the grids with viewstate enabled since I need them for picking what is the value entered or chosen in all the grids to build dynamic sql.
 
As known issue, datagrid leads to large viewstate footprint and because of dropdowns containg large volume of data , viewstate is enormous in size and its leads performance issue on each post back.
 
How to reduce the viewstate content and improve performance with respect to my requirement .Any ideas!
 
I checked google, few articles says saving viewstate in server side.But storing large content of viewstate in session variables in server also will have performace issue. But that would be better than putting viewstate content in the page itself and getting post back with that huge content when viewed thro intenet.
 
Can you tell me the best way to go ahead. I have finished the query screen with full functionality.
 
any suggestion is welcomed.
 
Thanks & regards
Barani

GeneralGreat one!memberAbishek Bellamkonda20 Apr '05 - 21:51 
:-DGreat article
 

 
AbiBaby ( Abishek Bellamkonda )
=(:*
GeneralI love an unintentional Pun!sussAnonymous21 Apr '05 - 4:13 
"Great Article"
 
hahahahah.
 
Which I find funny because articles ("a", "the" , "an") are suspiciously absent from this submission.
 
Ahhhh. Funny.

GeneralRe: I love an unintentional Pun!memberAbishek Bellamkonda21 Apr '05 - 13:25 
If this was an english test, the author might have failed or got less marks if you assesed it.
 
Fortunatly its Tech article, you need just basic english.
 
=(:*
GeneralRe: I love an unintentional Pun!memberXagyg3 Jun '08 - 4:40 
Unfortunately, too many people agree with you on this concept.
 
If you demonstrate your inability to use ANY language correctly and efficiently, you evince a general trend that follows in your use of other languages...whether human- or computer-based.
 
For many, the visibility of someone being sloppy with English allows them to extrapolate the same lack of care using, say, a .NET language, rather than analyze the code to come to the same conclusion.
GeneralRe: Great one!sussBugsbuddy21 Apr '05 - 21:56 
but it is useless if the DataGridItem's VS is disabled. when the page is postbacked by other controls which wouldn't bind the DG use datasource, the DG will show us a table without any data-row contained.
GeneralRe: Great one!memberAbishek Bellamkonda23 Apr '05 - 12:34 
Well, there will be both good and not so good things in almost everything. Its upto the reader to see half full or half empty. I was looking at Numbers this person brought up with regarding ViewState and the otherside of you condition.
 
I personally store ViewState on server (Database), i have code to use it on session or file system. It works VERY well, no problems seen ever so far. Session is faster, but takes up servers memory quickly. Each request gets a GUID and that is stored as hidden variable. Its all done in my BasePage. I disable ViewState or enable it for control/page based on situation.
 
AbiBaby ( Abishek Bellamkonda )
=(:*
 
=(:*
QuestionHow different is this approach?memberSathish Kumar K11 Apr '05 - 17:13 
Hi,
 
How different is this approach of reducing viewstate for every item?
 
<asp:datagrid id="DataGrid1" runat="server" EnableViewState="false"
                        BorderStyle="None" BorderWidth="1px" BorderColor="#CCCCCC"
                        BackColor="White" CellPadding="5">
 
i.e We could also disable viewstate across the Datagrid in one step. Is your approach reduces viewstate?
 
Sathish Kumar K
AnswerRe: How different is this approach?memberRobert V11 Apr '05 - 18:26 
Yes you can do that. And then paging, sorting etc. don't work either.
 
The point of the article is how to reduce viewstate but retain paging and sorting which both require viewstate for a datagrid to be one.
 
Unless you completely create your own.

GeneralRe: How different is this approach?memberSathish Kumar K13 Apr '05 - 6:19 
Thanks Robert for the clarification.
 
Now I have understood the advantage of this approach.
GeneralRe: How different is this approach?memberspvarapu29 Sep '05 - 21:38 
Here by disableing viewstate to entire datagrid we can still work with paging and sorting. Just check this link and give me ur comments
 
http://authors.aspalliance.com/JimRoss/Articles/DataGridDiet.aspx?print=1[^]
 
Sreenivasulu Palavarapu
Infinite Computer Solutions,
Bangalore.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 11 Apr 2005
Article Copyright 2005 by Daniel Fruzynski
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid