ASPAlliance.com : The #1 ASP.NET Developer Community : A Diet for the Datagrid
ASPAlliance.com : The #1 Active Server Pages .NET Community The #1 ASP.NET Community
Search   Search

Subscribe   Subscribe

Powered by ORCSWeb Hosting


Site Stats


Powered By ASP.NET
 
Featured Sponsor

Featured Columnist


Featured Book
Inside C#
Inside C#

Find Prices
Read Review


New! asp.netPRO

We publish our articles in the standard RSS format.

Powerful .NET Email Component

Code Sharing Software
<- Old Dog, New Tricks Printer Friendly Version 

Putting the DataGrid on a Diet

By Jim Ross

The datagrid may be the most powerful component in ASP.NET. If not, it certainly has to be on any short list. But the Datagrid is a pig. It creates HUGE amounts of Viewstate. For example, a simple grid with 3 or 4 columns and limited to only 10 rows per page can easily generate 2-3k of viewstate. Not a lot, you may think. About the size of a small icon or other small graphic. But the situation can rapidly become worse. Add a field or two, expand the rows from 10 to 20, and before long you're passing more viewstate than rendered page content around. And remember, that viewstate has to go both ways--it slows down the page loading to the client, AND, because it has to come back to you on a postback, it slows that down too.

Things are worst for users on slow dialup connections, and may not be noticeable at all to users on a corporate network with fiber backbones and 100mb Ethernet local segments. In between are folks with high-speed connections, such as cable. Those connections typically have very good download speed, but the upload is frequently throttled way back. For example, where I live, the only cable company in town provides me with a respectable 1mb/sec download speed, but only 128kb/sec back up. So when I have to post a form with a huge viewstate, the pause can be noticable.

Why not just turn off Viewstate then?

So why not just turn Viewstate off? Simple--it provides a lot of benefits to compensate for the baggage it adds. If you want to find out how much it provides, just create a simple form with a Datagrid and set the grid up for paging. The code to support paging might look something like this:

Private Sub myGrid_PageIndexChanged(s As Object, e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles myGrid.PageIndexChanged
    myGrid.CurrentPageIndex = e.NewPageIndex
    GetGridData() ' or however you populate your datasource
    BindMyGrid()  ' I always put this into its own method

End Sub


With Viewstate on, this code will cause the grid to display page 2 of its data. But with Viewstate off, your PageIndexChanged method is never even called, and your grid disappears. Not worth it, it would seem. But there is a way to turn off viewstate and still have your paging. Actually there are a couple of ways to put the grid on a diet by slimming down viewstate. In this article we'll show you one of them, and in a follow-up (hopefully next week) we'll show you the other.

How Turn off Viewstate and retain paging in the Datagrid

The reason the grid disappears when Viewstate is turned off is that when this is done, the grid must be rebuilt from its datasource on every postback. Normally, the grid is "re-hydrated" by the viewstate restoration process, but when it doesn't have any viewstate, there is nothing to rebuild it. It seems that this even includes hooking up the handlers for the grid's events--such as PageIndexChanged--and that is why our PageIndexChanged was never called. So what can we do? Simple. We break one of the rules we usually follow rigorously in writing a Page_Load method. We rebind the grid in Page_Load on every postback.

Private Sub Page_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load

    ' here are those two helper functions again.
    ' You may prefer to do things differently, 
    ' which is fine, but just be sure that the grid gets
    ' re-bound to a populated datasource.
    GetGridData()
    BindMyGrid()

End Sub


You will find that if you add this to your page load your grid will no longer disappear. And paging will even work again. Hallelujah! If all you are doing is displaying a list of "stuff" for people to look at, you're done. Or if your grid just contains, perhaps, hyperlinks that go to another page without posting back to the grid's page, you're still in good shape.

Unfortunately, in the real world there are other requirements. Often the specifications require that you provide a way for the users to interact with the items on the grid itself. The simplest interaction is just to select an item, perhaps by clicking the "Select" column on the right-hand side of the grid. Well on our "view-stateless" grid, as we have it to this point, if anything but a paging request causes the page to post back, the grid will revert to page one. For example, if the grid were displaying page three, and the user clicked the Select button on the fourth item, the grid would indeed display the fourth item as selected--but on page one, not page three. Ungood.

Keeping track of the current page through postbacks

What we need is a way to keep track of the page through postbacks. For that, we turn to our old "friend" who we just banished from the Datagrid--Viewstate. Only now we use Viewstate sparingly, to just store the grid's current page index. We will change three methods on the page do this: Page_Load, the grid's PageIndexChanged, and our "helper", BindGrid. Here are the three methods, with changes highlighted:

Private Sub Page_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
 

    ' Set an initial page for the datagrid
    If Not IsPostBack Then
        Viewstate("pageIndex") = 0
    End If

    ' here are those two helper functions again.
    ' You may prefer to do things differently, 
    ' which is fine, but just be sure that the grid gets
    ' re-bound to a populated datasource.
    GetGridData()
    BindMyGrid()

End Sub

    In Page_Load, we save an initial page number for the grid in Viewstate. Note that we save a "0", not a "1", because the grid's page numbering is actually a zero-based index. Page 1 is CurrentPageIndex 0. Now let's look at the thus-far ignored "BindMyGrid":
 
Private Sub BindMyGrid()
 

    ' Set the grid's page from viewstate
    myDataGrid.CurrentPageIndex = CInt(Viewstate("pageIndex"))

    ' now bind the grid to the class member datasource that
    ' is created by "GetGridData".
    myDataGrid.DataSource = Me.GridDataSource.Tables(0).DefaultView

End Sub

  
    This is how we get the CurrentPageIndex to the grid. Normally, if the grid's viewstate were turned on, the grid would remember the CurrentPageIndex itself. But now we have to help it, so we set the CurrentPageIndex from the value in our own Viewstate.

You can probably figure out the last step for yourself by now, but just for completeness, here is the last thing we need to do to restore paging to our grid--we need to modify our PageIndexChanged handler:

Private Sub myGrid_PageIndexChanged(s As Object, e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles myGrid.PageIndexChanged
   

    ' not this way-> myGrid.CurrentPageIndex = e.NewPageIndex
    ' Instead:
    ' save the new page index to our own Viewstate
    Viewstate("pageIndex") = e.NewPageIndex

    ' 8/26/2003 No need to get data again here because
    ' we populated our dataset during PageLoad
    BindMyGrid() 

End Sub

And that does it. Now the "stateless" grid can be paged, and will retain the page number during other postbacks.

Limitations

This technique will work fine for any read-only grid. Unfortunately, if you want to be able to edit within your grid, it will not. The necessity of re-binding the grid in Page_Load means that any user input will be overlaid on every postback, and you will have to resort to "Classic" ASP methods to retrieve the user input from the Form's items collections and restore those values to the edit controls before returning a response to the user. Not very desirable, but it will work. However, there is a better way to reduce the DataGrid's viewstate, allow editing, and still retain the benefits of ASP.NET's event handling capabilities. We will see that in my next column.

<- Old Dog, New Tricks Printer Friendly Version 


 Copyright © 2000-2003 ASPAlliance.com  Page Rendered at 11/21/2009 3:08:37 PM