Concept
With the rise of ASP.NET 2.0 AJAX Extensions 1.0, developers were fascinated by the great AJAX Server controls, but they missed that some of them might be harmful if they didn't really know how to use them in a proper way. One example is when there is a need to have a button (Select button) in every row, that when clicked shall cause an asynchronous postback to update an area on the page that is surrounded by an UpdatePanel.
A solution might be to place the entire GridView inside an UpdatePanel, and since the UpdatePanel has a property called "ChildrenAsTriggers" that has a value of "true" by default, then any postback that goes out of the GridView would cause an asynchronous postback.
But wait!!
Doesn't this mean that every time, a button in a specific row is clicked, the entire GridView is posted-back to the server and then again on the way back, GridView is refreshed? Yes, this is true and that's why I mentioned above, AJAX Server Controls should be used in a proper way, i.e. Use but Don't Over Use!!
Solution
The situation is as follows. There is an UpdatePanel with a Label inside that holds the current DateTime value. Below this UpdatePanel there is a GridView that lists data from the Vendors data table located in the AdventureWorks Database. For every row, there is a Select Button that will should cause an asynchronous postback and hence updating the Label located in the above UpdatePanel. Here is the ASPX markup:
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="lblName" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1"
AutoGenerateColumns="False" onrowdatabound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="ActiveFlag" HeaderText="ActiveFlag"
SortExpression="ActiveFlag" />
<asp:BoundField DataField="VendorID" HeaderText="VendorID"
InsertVisible="False" ReadOnly="True" SortExpression="VendorID" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:TemplateField HeaderText="Command">
<ItemTemplate>
<asp:UpdatePanel ID="gridUpdatePanel" runat="server">
<ContentTemplate>
<asp:LinkButton ID="lbtnSelect" Text="Select" runat="server"
CommandName="Select" onclick="lbtnSelect_Click" />
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:AdventureWorksConnectionString %>"
SelectCommand="SELECT TOP 5 [ActiveFlag], [VendorID], [Name] FROM [Purchasing].[Vendor]" />
The smart idea is to place only the column that holds the Select Button in an UpdatePanel, notice the bold area in the code above. Then when this LinkButton is clicked, an Async Postback will proceed and update the content of the Label inside the main UpdatePanel. In addition, you need to set the UpdateMode on the first UpdatePanel to "Conditional" so that not every Async postback on the page causes it to refresh its content.
What is left is to show the code behind of the LinkButton's event handler in C#:
protected void lbtnSelect_Click(object sender, EventArgs e)
{
this.lblName.Text = DateTime.Now.ToString();
this.UpdatePanel1.Update();
}
As you can see a call to the UpdatePanel's Update() method is executed. This will cause the UpdatePanel1 to have its content refreshed on the client-side. As you saw before, the UpdatePanel didn't define any triggers and had its UpdateMode set to Conditional, so the only way to get its content refreshed is to call its Update() method manually.
When testing this code in FireFox and turning on Firebug, we can see the response coming back from the server as:
62|updatePanel|UpdatePanel1| <span id="lblName">2/18/2008 6:51:14 PM</span> |165|updatePanel|GridView1_ctl02_gridUpdatePanel| <a id="GridView1_ctl02_lbtnSelect" href="javascript:__doPostBack('GridView1$ctl02$lbtnSelect'
,'')">Select</a> |165|updatePanel|GridView1_ctl03_gridUpdatePanel| <a id="GridView1_ctl03_lbtnSelect" href="javascript:__doPostBack('GridView1$ctl03$lbtnSelect' ,'')">Select</a> |165|updatePanel|GridView1_ctl04_gridUpdatePanel|
<a id="GridView1_ctl04_lbtnSelect" href="javascript:__doPostBack('GridView1$ctl04$lbtnSelect','')">Select</a> |165|updatePanel|GridView1_ctl05_gridUpdatePanel|
<a id="GridView1_ctl05_lbtnSelect" href="javascript:__doPostBack('GridView1$ctl05$lbtnSelect','')">Select</a> |165|updatePanel|GridView1_ctl06_gridUpdatePanel|
<a id="GridView1_ctl06_lbtnSelect" href="javascript:__doPostBack('GridView1$ctl06$lbtnSelect' ,'')">Select</a> |0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||704|hiddenField
|__VIEWSTATE/ViewState cut down
Oh, what went wrong? You can see that the entire GridView was refreshed! This defeats the purpose of what has been mentioned above!! Well, you never learn until you do the mistake! Let us think about it a bit, every row now holds an UpdatePanel, every UpdatePanel has the UpdateMode="Always" and ChildrenAsTriggers="True" -- Default values. This clearly explains why the entire GridView was refreshed upon clicking on the Select LinkButton.
How to solve this?
All what you need to do is add the following to the UpdatePanel located inside the GridView:
UpdateMode="Conditional" ChildrenAsTriggers="false"
This tells the UpdatePanels located inside the GridView, not to refresh on every Async Postback and not to get refreshed by any event that occurs from within the contents of the UpdatePanel. In other words, never refresh this UpdatePanel. This is true as long as you don't care about updating anything inside the GridView row. This is a good solution as long as what you want to peform is refresh other content outside the GridView.
Now, running the same code again and testing using FireFox and Firebug, you can see how the response has been cut down to only the ViewState and the content of the upper UpdatePanel that contains the Label to be updated:
62|updatePanel|UpdatePanel1| <span id="lblName">2/18/2008 7:01:01 PM</span> |0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||704|hiddenField|__VIEWSTATE| ViewState cut down
Can you see how much you have gained by adding those two properties? Now you have your problem solved with a GridView containing a button to update an external UpdatePanel and with a good performance hit! Imagine how helpful this would be for a larger amount of data being displayed in the GridView?
Hope you enjoyed this article!
Regards