|
|
|
|
|||||||||||||
Putting the DataGrid on a DietBy 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
How Turn off Viewstate and retain paging in the DatagridThe 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
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 postbacksWhat 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 ' 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 ' now bind the grid to the class member datasource that
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 ' 8/26/2003 No need to get data
again here because And that does it. Now the "stateless" grid can be paged, and will retain the page number during other postbacks. LimitationsThis 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.
| |||||||||||||||
| Copyright © 2000-2003 ASPAlliance.com Page Rendered at
11/8/2009 9:39:16 AM |
|||||||||||||||