Bug with DataGrid that is rebound on every request

G

Guest

Most of the time you bind a datagrid when it's not a PostBack. The DataGrid then uses ViewState to remember all the data to rebuild it on subsequent postbacks. Thats great when it is expensive to grab the data, like running a sql query might be

If you've ever done a View Source on a page with a big datagrid, you've seen first hand how LARGE the viewstate can get. The data I'm binding to the grid is readily available via a business object that lives in a static class. This means that rebinding the data to the grid on every request is preferable to allowing the viewstate to be so bloated, since accessing the data doesn't cost any expensive sql queries or anything

(here comes the issue

However -- even though I dont want the data of the grid to be stored in viewstate on the page, I *do* want to take advantage of all the other properties that are stored in viewstate. For example, the SelectedIndex is stored in viewstate so the selected item is remembered across postbacks. So what I'm doing is something like this (C#)

protected override OnInit(object sender, EventArgs e

grd = new DataGrid()
grd.DataSource = SomeDataSource
grd.SelectedItemStyle.Font.Bold = true
// ..
// ... add all the columns, including a button column with commandname = "select
// ..
grd.DataBind()
Controls.Add(grd)


Since I'm DataBinding the grid BEFORE it is added to the controls collection, the actual databound data added to ViewState does not end up persisted in the VIEWSTATE hidden form field, because the grid was not yet tracking its viewstate when it was bound. Yet viewstate is still enabled for the grid, so events that change its properties will still be persisted (such as setting the SelectedIndex). This accomplishes my goal. BUT -- here's the kicker. If someone clicks on the button column to SELECT one of the rows, the row shows up as selected (BOLD) -- and the selected index is saved in ViewState (I can see it). But after the NEXT postback (by clicking on a button somewhere other than the grid), the selected item is no longer BOLD. This is true even though the ViewState on the grid still contains the selected index, and the SelectedIndex property still contains the right value! It's just that the selected style is lost. And yes, I'm setting the selected style to bold font on every request

As far as I can guess, its happening because when I am calling DataBind() on the grid, it immediately figures out which item is supposed to be 'selected' and sets its item type to ListItemType.Selected. But since I've databound it BEFORE viewstate is loaded, it doesn't think any of them are selected. But then at a later point the ViewState is restored, and the SelectedIndex returns the correct value -- but its too late, the item was not marked as a selected item, so the selected style does not get applied to it. It's not just that the style isn't applied -- If I loop through the grid's Items collection and look at the ItemType of the item that is supposed to be selected, it is *not* ListItemType.Selected

This seems like a bug in the grid to me -- I mean, if SelectedIndex has the right value, and it is being persisted across postbacks, then the SelectedItemStyle aught to be applied. Surely someone has had the need to use a datagrid without impacting ViewState size and without completely disabling viewstate on the grid (because then the SelectedIndex is lost on postback, for example)

If I change the code so that the grid is databound after it is added to the controls collection, then the selection works perfectly -- BUT the viewstate contains all the data, which I don't need

There has to be a way to have the grid populated with data without that data being persisted in viewstate, while also not completely disabling viewstate on the whole grid

Help
 
G

Guest

After rebinding the data on postback, try setting SelectedItemIndex to the persisted SelectedItemIndex when you detect the postback. That should assert the SelectedItemStyle and resolve any other state ambiguities precipitated by your clever hack.
 
D

Dave Reed

That will probably resolve the selected style issue, but imagine a grid with
an EditItemIndex. When databound, the datagrid fires ItemDataBound and
passes a particular ItemType. The ItemType for the row being edited is going
to suffer the same issue caused by the way SelectedIndex is handled. But
just resetting the EditItemIndex won't help since the item has already been
created, and the columns have all instantiated their ItemTemplate rather
than their EditItemTemplate.

Resetting the SelectedIndex right after ViewState is loaded -- now that
sounds like a hack. I wouldn't consider binding the grid before adding it to
the collection to be a hack at all... its common practice to assign default
values to dynamic controls just before adding them to a page. The reason is
if you were to set properties after adding it to the page, those properties
would be tracked and persisted in viewstate on the page, even though they
are default values. Default values aren't supposed to be persisted, because
theres no reason to ... the value is going to be restored by code on the
next postback, so why is it in viewstate too? By binding the grid first, I'm
saying "here is your default data... now do your thing." For example, you
can do it with a label like so:

l = new Label();
l.Text = "default text";
Controls.Add(l);

If some other control ends up changing the label's text for some reason, the
label persists the new value in viewstate, and on subsequent posts, the text
is maintained, even though I'm explicitly setting a default value on every
post. Its all because I'm setting the default value before viewstate is
being tracked (IsTrackingViewState). This is exactly how the framework
assigns values that you specify declaratively on an aspx page. Just check --
override OnInit, and check the value of a label that is declared on the
page. It should be the same as what it says in the aspx code. But place 100
of those labels on the page, or 1000, or 10000, and you wont see viewstate
get any larger at all. Now do the same thing with a dynamicly created
label -- set its text before adding it to the control collection. Then set
it after you add it to the control collection -- if you do the ladder,
viewstate will take a hit, and there's no reason for it to.

Obviously the grid's DataBind() wasn't designed with that use in mind. Which
means I'm back to my original problem ---

How do I get a grid NOT to persist all its data in viewstate, without
disabling viewstate on the entire gird?


mklapp said:
After rebinding the data on postback, try setting SelectedItemIndex to the
persisted SelectedItemIndex when you detect the postback. That should
assert the SelectedItemStyle and resolve any other state ambiguities
precipitated by your clever hack.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top