Was the asp.net GridView ever capable of using ViewState? - c#

I'm working on an old site that originated as a Visual Studio Website project, and which I'm converting to a Web Application in addition to other work. One page on the site uses a GridView, and sets the DataSource in code-behind using a DataTable. The GridView exposes a couple of BoundFields, as well as one TemplateField that has a checkbox in it. The GridView is configured to use EnableViewState.
<asp:GridView ID="Results" runat="server" AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333" GridLines="None" EnableViewState="true">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:BoundField DataField="Type" HeaderText="Type"/>
<asp:BoundField DataField="ProcessDate" HeaderText="Process Date" />
<asp:BoundField DataField="Classification" HeaderText="Classification" />
<asp:BoundField DataField="Email" HeaderText="Email" />
<asp:TemplateField HeaderText="Notify?" ItemStyle-HorizontalAlign="Center">
<EditItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" onclick="EnableSubmit(this);" />
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" onclick="EnableSubmit(this);" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
The page also has a Submit button, and in the _Click handler, the code attempts to grab Results.Rows, and then digs around in order to determine which rows have their checkboxes checked. It does its subsequent processing based on the checked rows.
The old site code does IsPostBack checking, and only calls DataBind when it's false.
The page doesn't define either EnableViewState or ViewStateMode, which means they're both defaulting to true, according to MSDN.
There's no call to DataBind in a master page or anything.
The old site code does not do any manual persisting to the ViewState dictionary.
Amazingly, the production version of this site actually works.
Since I've been working on this, I've found only threads and articles discussing how GridView doesn't actually use ViewState, and how in order to use data sent to the user, the DataTable used as the DataSource must be manually inserted into ViewState in the code behind, etc.
The version of the site I'm working on has been converted to a Web Application project, and it's targeting .NET 4.5. When I debug the site and break in Page_Load or Submit_Click, the Results GridView has a null DataSource and the Rows property has 0 count. This seems to agree with the current conventional wisdom concerning how GridView "works."
I'm well aware that for what this site is doing, this is a heinous implementation, and there are much better ways to do it. However, what I'm most concerned about is that I can't find any explanation as to how the old version is working.
Did GridView change at some point in its history to ignore its EnableViewState property? What does EnableViewState on GridView actually do? Could it be a difference between Website and Web Application projects?
How can this possibly be working?
UPDATE: Based on Bert Evans' example page, I tried out this modified page.
<%# Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
public class Thing
{
public int ID { get; set; }
public string Name { get; set; }
}
IEnumerable<Thing> Things
{
get
{
var things = new List<Thing>();
things.Add(new Thing { ID = 1, Name = "One" });
things.Add(new Thing { ID = 2, Name = "Two" });
things.Add(new Thing { ID = 3, Name = "Three" });
things.Add(new Thing { ID = 4, Name = "Four" });
things.Add(new Thing { ID = 5, Name = "Five" });
return things;
}
}
void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ThingGridView.DataSource = Things;
ThingGridView.DataBind();
}
pageLoadLabel.Text = string.Format("On page Load, row count: '{0}'", ThingGridView.Rows.Count);
}
void OnClickMe(object sender, EventArgs e)
{
onClickLabel.Text = string.Format("On click, row count: '{0}'", ThingGridView.Rows.Count);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView runat="server" ID="ThingGridView">
<Columns>
<asp:BoundField HeaderText="Name" DataField="Name" />
</Columns>
</asp:GridView>
</div>
<asp:Button runat="server" ID="ThingButton" Text="Click Me!" OnClick="OnClickMe" />
<asp:Label runat="server" ID="onClickLabel" Text="[set on click]" />
<asp:Label runat="server" ID="pageLoadLabel" Text="[set on page load]" />
</form>
</body>
</html>
The only differences are the labels that print out the row count in the page body. When executing this page. the first Page_Load call prints row count 5 to the page; however, in postback, the row count is 0 in both page load and the OnClick method.

Databinding is the process of translating the specified datasource for a control into a control tree that is rendered to the page. For GridViews, essentially, setting the DataSource property and calling the DataBind method translates an IEnumerable, or an IEnumerable extracted from another source like a DataSet or DataTable, into an HTML table with controls containing the data.
Each of the controls rendered into the table cells maintains it's own ViewState, so that when the page is posted back to the server, the GridView rebuilds the control structure, and populates the controls with the data in the ViewState (or rather, the Page initiates the rebuilding of the control structure and the GridView just participates).
The DataSource is not saved to the ViewState, only the state of the rendered controls.
Disabling the ViewState on a GridView prevents it from saving certain elements of it's own state, which will prevent it from being able to do things like pagination and sorting. Furthermore, if you disable the ViewState on the GridView, and you perform a postback (trigger an event on the client side that submits the page back to the server), then the GridView will show nothing when the page is re-rendered, because EnableViewState is inherited and the child controls will be prevented from saving their own state. The only way to get a GridView with a disabled ViewState to show data again after a post back would be to either re bind the data (call DataBind again with a data source that has data) or to have manually enabled ViewState on the child controls contained inside the GridView with the disabled ViewState. You mentioned that the DataBind on the page you are working on is guarded with !IsPostback, so it is only binding on the initial load of the page.
I don't know of anything changing such that the GridView at one point in time saved the DataSource, I believe this is how it always worked.

Thanks to Bert Evans and his example page I eventually isolated the problem. The bug is actually in the remarkably poor MSDN code example for UnityHttpModule, which integrates Unity DI with ASP.NET. UnityHttpModule detailed at https://msdn.microsoft.com/en-us/library/ff664534(v=pandp.50).aspx.
In addition to not actually even compiling as listed, the class wires up the DI code on the InitComplete event, which takes place before ViewState is loaded, as described in this article: ASP.NET 4.0 GridView OnRowEditing events not firing when using Unity 2.0 http module. In my case, moving the DI code to execute on PreLoad fixed my problem.
Finally, for completeness, and for anyone else having problems with the MSDN Unity DI HttpModule, a different SO thread also provides a working example: ASP.NET Dependency Injection HTTP Module (MS Enterprise Library).

Related

Linked Button inside grid view causing full post back when using update panel with grid view

There is a button outside update panel, the click event of the button binds grid view.
Grid view is inside the update panel and there is a link button inside the grid view.
Link button is causing full post back, i have looked online and tried different things but no luck so far.
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<table>
<tr>
<td>
<asp:UpdatePanel ID="ContentUpdatePanel" runat="server">
<ContentTemplate>
<asp:GridView ID="gvMasterData" runat="server" AutoGenerateColumns="false" Width="200px" class="display">
<Columns>
<asp:TemplateField HeaderText="registration date" ItemStyle-Width="50">
<ItemTemplate>
<asp:Label ID="lblRegistrationDate" runat="server" Text='<%# Eval("registration_date") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="completed" ItemStyle-Width="50">
<ItemTemplate>
<asp:LinkButton Text='<%# Eval("completed") %>' ForeColor="Black" Font-Underline="false" runat="server" CommandName="Completed" CommandArgument="<%# Container.DataItemIndex %>" /> </ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="pending" ItemStyle-Width="50">
<ItemTemplate>
<asp:LinkButton ID="MarkAsCompleteButton" Text='<%# Eval("pending") %>' ForeColor="Black" Font-Underline="false" runat="server" CommandName="Pending" CommandArgument="<%# Container.DataItemIndex %>" /> </ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
</td>
</table>
Code Behind
private void gvMasterData_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton lb = e.Row.FindControl("MarkAsCompleteButton") as LinkButton;
ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(lb);
}
}
Try to see this
Full postback triggered by LinkButton inside GridView inside UpdatePanel
When you use a update panel then the standard web page life cycle DOES occur. This is what we call a partial post back.
So the forms on-load event and near all of the standard web forms events WILL fire.
The only difference is that in these partial post backs, then the code stubs (code behind) can only modify controls inside of the panel - not controls outside. The code in the panel can certainly grab/use/look at and consume controls outside of the panel, but the values will be somewhat "static" or more clear such values will be the same when the full page was rendered since the last full page post back.
So are you confused or surprised that you seeing a post back? you will and you do!!
So perhaps you are seeing a post back (you will and do). However that post-back is not a full page post back. Any button or event that fires inside of the update panel will cause a post-back - but it is what we call a partial post back.
As such, then most of the web page standard events do fire - including the on-load event. As noted, the only difference here is that these partial post backs only sends up to the server the updated content inside of that up-date panel (not the whole page).
So you do of course in all cases will see events like on-load fire. And when the code behind stubs inside of that panel run, then as a normal course of action you can only deal with and modify controls inside of that panel with the code behind. If that code modifies controls outside of the panel, then in the classic standard "round trip" that occurs here DOES NOT include those controls outside of the update panel. So you can't and will not see the changes reflected in controls outside of the panel in that code behind that runs.
But a good old fashioned round trip DOES occur when using a up-date panel, it just that only controls and things inside of the panel make this classic round trip - not the whole page.
So update panels do and will cause post-backs, but they are considered partial ones.
So of course a update panel DOES cause a post-back - but it is only a partial post back. All of the classic round trip operations occur here - same as a full page post back, but it is limited to the update panel - not the whole page.
So it not clear if you "wondering" why you see a post back (you will and you do).
Or if you are actually seeing a whole page post back. So ZERO surprise that a post-back is being triggered here (that does occur). The only question then is the post back you are seeing is a full page (should not occur), or you just seeing a page post back that is the partial one?
As noted, you will see a post back for events run inside of the panel. And thus as a normal operation things like page on-load does and will fire when using a update panel.
In other words, the whole standard page round trip for a update panel code and trigger DOES occur. This is a standard classic round trip that occurs here. As noted, the only difference is that such round trips only include the content inside of the panel, and thus other controls on the page should not be touched nor re-freshed.

Loading Gridview

I have a gridview that is populated from the code behind, and has about 300 rows. When I try to access the page containing it, everything loads, and then about 5 seconds later, the program quits and this error message appears:
If I press continue, the application stops running. However, when I look at the page, all of the data has loaded into the gridview (but of course my links, etc, don't work because the session has stopped running).
If I put less data in the table that populates the gridview, I do not get an error (it works with about 30 rows--I'm not sure the exact point where it becomes too much data). Anyway, since it is the exact same code but just less data, I know that I don't actually have an infinite loop or infinite recursion like the message suggests.
Here is the html for the gridview:
<div id="dvGrid" class="gridTable">
<asp:GridView runat="server" ID="GridView1" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="Edit" HtmlEncode="false" HeaderText="" HeaderStyle-Wrap="false" SortExpression="Edit" />
</Columns>
</asp:GridView>
</div>
Here is where it is populated in the code behind (this is in the Page_Load method):
DataTable dt = OpenWeather10Day.DBQueries.GetHistoricalData(_Zip);
dt.Columns["Date"].SetOrdinal(0);
GridView1.DataSource = dt;
_LinkColIndex = dt.Columns["Edit"].Ordinal;
_CommentsColIndex = dt.Columns["Comments"].Ordinal;
GridView1.DataSource = dt.DefaultView;
GridView1.DataBind();
And here is the OnRowDataBound function:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{//remove double edit column and add a div in comments column to make it the correct size
TableCell cell = e.Row.Cells[0];
e.Row.Cells.RemoveAt(0);
e.Row.Cells.RemoveAt(_LinkColIndex);
e.Row.Cells.Add(cell);
if (e.Row.RowType == DataControlRowType.DataRow) {
TableCell commentsCell = e.Row.Cells[_CommentsColIndex];
HtmlGenericControl div = new HtmlGenericControl("DIV");
div.Attributes.Add("class", "innerDiv");
div.InnerHtml = commentsCell.Text;
commentsCell.Text = string.Empty;
commentsCell.Controls.Add(div);
}
}
I have discovered that the error is with my "edit" column. If I delete the edit column from the table and get rid of all of the code related to it, all 300 rows load with no problem and the page is still active. The problem is that the edit column is critical to my page, so that is not a possible solution.
I've looked into pagination on scroll, but I can't find an example/demo that does exactly what I need or is simple enough for me to follow (I'm pretty much a complete beginner). I also don't think that it should be necessary to implement pagination; it's okay if the page takes a few seconds to load. My real problem/question is with the stack overflow that causes the session to quit. I have no idea what it is about the edit column that is causing this to occur, but somehow I need to fix this so that accessing this page doesn't quit the entire session. I am willing to add pagination on scroll if it is the only option, but like I said, I haven't been able to figure it out yet. I'm also not sure that it would fix the problem. I'm happy to post any other code, etc, if it'd be at all helpful!
Can you explain what is in your Edit column? Is it a Url, preformatted HTML? What will it do?
You are seeing 2 Edit columns because you have one added in your GridView, then you are adding a second one when you bind your data. Use the AutoGenerateColumns property to prevent this, then add in your other columns.
Example
<asp:GridView runat="server" ID="GridView1"
AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="Edit" HeaderText="Edit" />
<asp:BoundField DataField="Date" HeaderText="Date" />
<asp:TemplateField HeaderText="Comments">
<ItemTemplate>
<div class="innerDiv">
<%# Eval("Comments") %>
</div>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
You can use a TemplateField to put in the HTML in to your Comments column and get rid of
OnRowDataBound="GridView1_RowDataBound"

When does a Gridview have a null DataSource?

I've read multiple sources that say Gridview's do not persist the Gridview.DataSource property on postback. My understanding is that in term's of ASP.NET, a postback is any page load that is not the first pageload (see MSDN).
I've got a situation with 2 very similar gridviews.
GvOne.DataSource is null on postback.
GvTwo.DataSource is NOT null on postback.
The only big difference outside of a few differing columns is GvOne is populated with the Entity Framework and LINQ. GvTwo is populated by a DataTable filled by a SqlDataAdapter.
Further, GvOne and GvTwo have a TemplateField with a TextBox that I use to gather user input. Both use the same code to pull the TextBox.Text on postback:
TextBox tb = (TextBox)GvOne.Rows[i].FindControl("actualTxt");
GvOne properly gathers tb.Text. GvTwo always finds the tb.Text value to be 0.
Basic Gridview code:
<asp:GridView ID="GvOne" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Return">
<ItemTemplate>
<asp:TextBox id="actualTxt" runat="server" Text='0' Width="40px"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
...
</Columns>
</asp:GridView>
<asp:GridView ID="GvTwo" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Order">
<ItemTemplate>
<asp:TextBox id="actualTxt" runat="server" Text='0' Width="40px"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
...
</Columns>
</asp:GridView>
Changing GvTwo to use Entity Framework and LINQ is a potential solution, albeit a major undertaking. Does anyone know what is going on here?
UPDATE (See my comment on Joel Etherton's Answer)
Due to popular demand here is the code to populate the gridview within Page_Load event for GvTwo (GvOne is similar):
ordersGV.DataSource = dataSetObject.Tables["activeParts"];
ordersGV.DataBind();
Searching through the code behind I found no other references to ordersGv.Datasource and no other events that are hooked into associated with the page life cycle.
Gridviews do not persist the datasource across postbacks. If you have a gridview that has a non-null datasource then you must be filling that datasource somewhere in your code. It would be instructive to travel through your event cycle to find where exactly the population of the datasource is occuring on postback.
what does your Page_load code look like?
GridView does not keep DataSource property populated over the postbacks for performance issues
Maybe the second gridview is rebinding the datasource on postback?

UpdatePanel and Repeater render page unresponsive after post-back

I have a page with an UpdatePanel that contains a Repeater and a text box with the number of items in the repeater. When I change the value, the page is supposed to post back and redraw the Repeater with the updated number of items. This works in principle, but the page ends up frozen after post-backs and does not accept any input - in IE 8 only. It works perfectly fine in Firefox. For instance, the context menu does not appear when I right-click in controls, and I cannot enter text in text boxes.
When I take out the UpdatePanel, the page works fine, but of course refreshes on every post-back event. This is not necessarily related to the Repeater on the page. I think I am seeing this on other pages. What's the trick here?
<asp:UpdatePanel ID="uPanel" runat="server" UpdateMode="Conditional"
EnableViewState="true" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:Panel ID="Panel1" runat="server" DefaultButton="btnSubmit">
<asp:TextBox ID="tbItems" runat="server" AutoPostback="true"
OnTextChanged="textchanged_Items"/>
<asp:Repeater id="rptItems" runat="server"
OnItemDataBound="repeaterItem_Databound">
<...>
</asp:Repeater>
protected void textchanged_Items(object sender, EventArgs e) {
try {
// this methods rebinds the repeater to a List after changing
// the number of items in the list
ReflowItemRepeater();
// This is not really necessary, since Databind() appears to
// cause an update. I tried it anyways.
uPanel.Update();
}
catch (Exception ex) {
ShowError(this, "Error displaying the item list.", ex, true);
}
}
I ended up removing the update panel.
One month later, different page, I am still and again fighting this. The situation is the same.
An update panel, a repeater (actually 2 nested repeaters), and a control in the repeater that fires a postback event. The server processes the event correctly and returns control, but the browser (IE8) never refreshes the update panel. The page is unresponsive, as if in some sort of dead-lock situation. I can unlock it by clicking on a button that fires another postback event (also in the update panel). But the text boxes in the panel are not clickable or editable when this happens.
Also, it happens only the first time. Once I have "freed up" the lock, or whatever it is, it will not happen again on this page, even when I repeat the exact same steps that led to it.
When this happens, the JIT debugger does not report anything.
I would actually set Triggers within your updatepanel.
I'm not sure you need to call .Update in your code behind as the updatepanel will be updated when the trigger occurs.
Try this:
My gut feeling is that it has something to do with the use of the OnTextChanged event. For kicks, try adding a button next to the text box, and reflow the repeater when the button is clicked instead. Does IE still freeze?
So I stripped this page down to the minimum and I found out what is doing it - the AjaxToolkit:CalendarExtender. If I take it out, everything works fine. Still, I would be curious to know if there is a workaround.
Here is a link to my test page. I will keep it up for a few days.
To see the issue, select "2" from the drop-down, then type something into the first quantity field and tab out. The cursor will blink in the next field, but it does not allow input. This happened in IE8, not in Firefox.
Edit: Actually, when I went back to the full page and removed the CalendarExtender, it was still not working. I do suspect that this issue has to do with controls posting back in the UpdatePanel, but I just can't pin it down. It seems seems to be one of these things where a combination of x things does not work, while any combination of (x-1) things does work.
Regarding the initial question, here's a working sample. I don't know if it's anyhow helpful, but just to make sure...
<%# Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"><title>Ajax Test</title></head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" />
<asp:UpdatePanel runat="server" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:Label runat="server" AssociatedControlID="txtTest">
Enter 'fruit' or 'vegetables':
</asp:Label>
<asp:TextBox
runat="server" ID="txtTest" AutoPostBack="true"
OnTextChanged="Handler_Test_TextChanged"
/>
<asp:Repeater runat="server" ID="rptItems">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate><li><%# Container.DataItem.ToString() %></li></ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
<script runat="server">
static readonly string[] Fruit = new string[]
{ "Apples", "Oranges", "Bananas", "Pears" };
static readonly string[] Veg = new string[]
{ "Potatoes", "Carrots", "Tomatoes", "Onion" };
void Handler_Test_TextChanged(object s, EventArgs e)
{
if(txtTest.Text == "fruit") rptItems.DataSource = Fruit;
else if(txtTest.Text == "vegetables") rptItems.DataSource = Veg;
else return;
rptItems.DataBind();
}
</script>

ObjectDataSource reacts to commented-out GridView?

I came across a very strange behavior in asp.net's ObjectDataSource, the description to reproduce is somewhat long, so bear with me while I set the scene.
So, imagine a trivial ObjectDataSource/GridView combo in a User Control. The ObjectDataSource calls a method which returns a List of objects, and the GridView shows these objects in tabular form:
<div runat="server" ID="ControlWrapper">
<asp:GridView ID="GridView1" AutoGenerateColumns="true" DataSourceID="ObjDataSource1" OnRowDataBound="GridView1_RowBound" runat="server">
</asp:GridView>
</div>
<asp:ObjectDataSource ID="ObjDataSource1" runat="server" SelectMethod="GetBundle" OnSelecting="FixDataSource_Selecting" OnSelected="FixDataSource_Selected"
TypeName="West.VitalSigns.Contracts.ProdFixController">
</asp:ObjectDataSource>
This approach will work with pretty much nothing in the code-behind. But let's say that we want to create n number of GridView-s depending on the contents of the database. So we comment out the GridView in the markup...
<div runat="server" ID="ControlWrapper">
<!--
<asp:GridView ID="GridView1" AutoGenerateColumns="true" DataSourceID="ObjDataSource1" OnRowDataBound="GridView1_RowBound" runat="server">
</asp:GridView>
-->
</div>
...and add something like this to the ObjectDataSource's Selected event handler:
protected void FixDataSource_Selected(object sender, ObjectDataSourceStatusEventArgs args)
{
HashSet<string> components = new HashSet<string<()
foreach (ProdFix fix in (List<ProdFix>)args.ReturnValue)
{
if (!components.Contains(fix.Component))
{
GridView v = new GridView();
v.ID=fix.Component.Replace(" " ,"").Replace("-","");
v.AutoGenerateColumns = true;
v.DataSource = args.ReturnValue;
v.RowDataBound +=new GridViewRowEventHandler(BundleGrid_RowBound);
ControlWrapper.Controls.Add(v);
components.Add(fix.Component);
}
}
}
This code works (or at least the un-simplified version works on my machine), so you decide to remove the commented-out section from the markup (don't want that cruft hanging around, after all!)
<div runat="server" ID="ControlWrapper">
</div>
When you do this, however, the code no longer works! The ObjectDataSource won't fire, which means that the Selected event will never happen, which means you won't get your GridView-s. It looks like ObjectDataSource is reacting to commented-out markup in the aspx file?
So, is this:
A bug in ASP.NET?
A non-standard way of dynamically creating GridViews?
A WTF that I shouldn't have tried anyway?
All of the above?
Your gridview control in the markup is not hidden, even with the comments. HTML comments do not apply to server-side tags. Use server side comments instead:
<% /* %> <% */ %>
or
<%-– and -–%>
24hrs later, I noticed that this approach to getting N number of grid-views was pretty silly. Instead of using an ObjectDataSource I refactored my code to just call the GetBundle method directly from Page_Load() and create the GridViews programatically.
cdonner has the answer correct about the server-side comments. I didn't realize that there was a difference.
This should work too, since you're "disabling" the tag with it:
<!--asp:GridView ID="GridView1" AutoGenerateColumns="true" DataSourceID="ObjDataSource1" OnRowDataBound="GridView1_RowBound" runat="server">
</asp:GridView-->

Categories