Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Just the other day, i was playing around with my DataControls nested inside an updatepanel. While this was working well, since everypostback was being done via an ajax callback, the amount of traffic going back and forth was simply way too bloated. It's easy not to notice at first, because everything is working as expected. however imagine a simple situation as the following pseudo code below. Things could be very complex, depending on how many datacontrols you have and the level of nesting.

<asp:updatepanel id="UpdatePanel1" runat="server">
    <ContentTemplate>
        <asp:GridView ID="GridView1" AutoGenerateSelectButton="true" 
        runat="server" 
        OnSelectedIndexChanged="GridView1_SelectedIndexChanged">
        </asp:GridView>
        <asp:DetailsView ID="DetailsView1" AutoGenerateEditButton="true"
            runat="server" OnModeChanging="DetailsView1_ModeChanging">
        </asp:DetailsView>
    </ContentTemplate>
</asp:updatepanel>

As you can note from the code, this is a simple GridView, which enables a DetailsView when a row in the GridView is selected. We then have an Edit button on the DetailsView that should send the DetailsView in edit mode when clicked. All nice so far. Now, this is going to work as advertised ofcourse, all postback is done silently in the background. But if you look closely enough, both the gridview and the DetailsView are contained within a single UpdatePanel, so obviously the postback caused from any child control nested in the updatepanel will cause the entire contents of the updatepanel to refresh and send back the collective rendered content to the client.

Below screenshots is the traffic analysed through firebug (a firefox extention). Hilighted data denotes the extra data we do not need rendered to the client.

As you can note from the screenshots above, my clicking the select button in the gridview, which should be launching the DetailsView in turn, while i'd only need the rendering of the DetailsView send back to me (since the gridview shouldn't need to change), i actually end up with both the rendering of the GridView and the DetailsView. Indeed, there is extra data(the GridView) being rendered which we do not need.


Ok, this is indeed a problem. Were doing things wrongly. So, how do we cause only the DetailsView to render back instead ? One might quickly think, let's put each into their own individual UpdatePanels ? :-)

So, let's try that. Nothing to be ashamed of. It was the first solution that came to my mind too :P

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <ContentTemplate>
                    <asp:GridView ID="GridView1" AutoGenerateSelectButton="true" runat="server" 
                    OnSelectedIndexChanged="GridView1_SelectedIndexChanged">
                    </asp:GridView>
                </ContentTemplate>
            </asp:UpdatePanel>
            <asp:UpdatePanel ID="UpdatePanel2" UpdateMode="conditional" runat="server">
         <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="GridView1" EventName="RowCommand" />
                </Triggers>
                <ContentTemplate>
                    <asp:DetailsView ID="DetailsView1" AutoGenerateEditButton="true" runat="server" 
                    OnModeChanging="DetailsView1_ModeChanging">
                    </asp:DetailsView>
                </ContentTemplate>
            </asp:UpdatePanel>

And here below is the screnshot of the traffic as seen through firebug. Hilighted data denotes the extra data we do not need rendered to the client.


As you can see, we ended up with the same data as before. Nothing has changed, even though we included them in two separate UpdatePanels. Strange ? Not really. If you think about it, both panels are included in the page, and by default, both panels have UpdateMode="Always" set on them, which causes both to refresh upon an async callback.

azzzz we have a problem indeed. Time to read the documentation :P

The first thing the docs hint about are two things : UpdateMode="Conditional" versus the Default which is "Always" and the second thing is  ChildrenAsTriggers="false" ; both of which are handy.

If my postback was being caused only by children in UpdatePanel2, i couldof just set UpdateMode="Conditional" on UpdatePanel1 and i'd actually achieve what i was after. Only UpdatePanel2's content will be send back to the client. However if you will note in my example above, a control in UpdatePanel1 is the one who is triggering the postback. This satisfies the "Conditional" bit and UpdatePanel1 also renders its contents. Again not what i'm after.

In effect, i've had to set both UpdateMode="Conditional" and also set ChildrenAsTriggers="false" on UpdatePanel1. This stopped the unwanted behaviour. ChildrenAsTriggers property has a proper explaination in the documentation, you can look it up. In short, it simply stops any direct children from making it refresh. This is good for us and what we are after.

That's just perfect. Using this combo, i can keep the panel i do not want updated, while letting the panel with the update trigger refresh at will. This also allows me to control who gets updated by calling the update method manually on the panel that interests me. For example if i edit a record in the detailsview and want to show the change in the gridview, i'd run the update operation and then right after that, call update on the panel that contains my gridview manually.

<asp:UpdatePanel ID="UpdatePanel1" UpdateMode="conditional" 
ChildrenAsTriggers="false" runat="server">
                <ContentTemplate>
                    <asp:GridView ID="GridView1" AutoGenerateSelectButton="true" runat="server" 
                    OnSelectedIndexChanged="GridView1_SelectedIndexChanged">
                    </asp:GridView>
                </ContentTemplate>
            </asp:UpdatePanel>
            <asp:UpdatePanel ID="UpdatePanel2" runat="server">
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="GridView1" EventName="RowCommand" />
                </Triggers>
                <ContentTemplate>
                    <asp:DetailsView ID="DetailsView1" AutoGenerateEditButton="true" runat="server" 
                    OnModeChanging="DetailsView1_ModeChanging">
                    </asp:DetailsView>
                </ContentTemplate>
            </asp:UpdatePanel>

here are the screenies, you can see, only the detailsview is now present in our callback. Just perfect.

While this is a simplistic example, had you many deeply nested updatepanels you can easily workout who gets updated and whose data gets rendered reducing bloat, using the same method i've mentioned above. Don't simply include EVERYTHING in one updatepanel or multiple and depend on the default, posting back un-necessary bloat on each callback. Firebug for Firefox and Fiddler for IE are both great tools for inspecting and analysing your callback traffic. Use either. I prefer firebug :p

Ok, so that was easy(just set UpdateMode="conditional" ChildrenAsTriggers="false"), nonetheless i ended up with quite a lengthy post :x

Published Wednesday, January 30, 2008 6:41 AM by alessandro

Comments

# Reducing UpdatePanel bloat by utilizing UpdateMode=

Wednesday, January 30, 2008 9:03 AM by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# re: Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Wednesday, January 30, 2008 9:05 AM by Doug

This is really good food for thought. I've seen pages that could probably benefit a great deal by applying what you explained here.

However, in the example you've given (selecting a row in the gridview and displaying the associated data in the detailsview),I don't think your approach is correct. :)

I haven't actually tested this, but... If you do not allow the updatepanel containing the gridview to update when a row is selected, then, although the details view will show up, the row selected in the gridview won't be highlighted (which is what, I think most people would expect to happen).

# re: Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Wednesday, January 30, 2008 9:41 AM by alessandro

Dough, that is correct, in that the selected row won't get hilighted. Not the most perfect example as you have already noted :-)

I've tried to keep things as simple as possible. It can get complex. In my case i have my detailsview normally in a modal popup so showing the selected row at the expense of pulling the entire contents of the gridview is not bringing much to the table (until the modalpopup has been closed, which is when i let the gridview refresh with the selected row).

Also due to the expensive nature of the operation, row selection can be done differently at the cost of extra effort naturally by the dev, maybe by selecting the row through script or other means. Ofcourse, at the end, the decision soley depends on the dev.

# re: Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Sunday, March 09, 2008 10:56 PM by johny

hey there.

i knew something did not sound right, when i read

"...and the second thing is  ChildrenAsTriggers='true', both of which..."

but, we all knew you meant "false"

# re: Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Monday, March 10, 2008 6:20 AM by alessandro

John, many thanks for correction :-)

# re: Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Sunday, August 10, 2008 3:31 PM by Yura Zaletskyy

Very interest and helpfull in may case. Thanks a lot.

# re: Reducing UpdatePanel bloat by utilizing UpdateMode="Conditional" and ChildrenAsTriggers="false"

Thursday, September 10, 2009 3:44 PM by jamesbond11

This is a good example but I ran into problems. My gridview which was working perfectly fine, had problems in paging when put in an updatepanel. It always showed the first page. When I went to second page, it showed the first page but in details view showed records from second page.

Setting UpdateMode="Always" and ChildrenAsTriggers="True"

resolved the problem.

Leave a Comment

(required) 
(required) 
(optional)
(required)