locked
Search form, results go to GridView in UpdatePanel; getting "Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request" RRS feed

  • Question

  • User1562156107 posted

    Hi...

    I've seen a lot of posts about how squirrely GridViews can be in UpdatePanels, but I've been nursing along an old implementation I was handed.  Lately the PM wanted to spiff it up a little, so I've been adding some cosmetic features, and it was going fine until I added a drop-down to change the number of results on the page.  Then I started getting viewstate load errors about the control tree not matching.

    We've got a search form with a bunch of different filters and a Search button on the main form and the Search button is a trigger for the UpdatePanel containing the results.

    First they wanted the total count of results in the pager of the GridView.  Fine, I added that.

    Next they wanted a checkbox in the filters section to control whether to display the total in the pager or not (because they were concerned about the cost of the extra query to get the real total).  I added that, and it worked without problem.

    Then I added a dropdown to let the user change the number of rows/page.  Now any time you change any filter *after* 1 pageview with the new result count you get the viewstate load error.

    What puzzles me is that I can change filters that result in a different row count or no results at all (e.g. First Name) and click Search as many times as I like and I don't get a viewstate load error.   I can check and uncheck the box to show the count in the pager (resulting in diddling of the pager rows) and click Search as often as I like and I don't get a viewstate load error.

    But changing the dropdown that changes the GridView.PageSize and then it gets very brittle and starts throwing viewstate load errors.  That's what puzzles me at the moment.

    The code change was to set

        ResultGV.PageSize = int.Parse(ResultCount.SelectedValue);

    just before selecting and binding the gridview in the Search button OnClick function.

    Any ideas?

    Thanks

    Mark

    Friday, December 5, 2014 4:30 PM

Answers

  • User1562156107 posted

    I've been playing with it a lot more today and am still not quite there on getting the behavior, but I did find that the viewstate exception was happening trying to read a Panel in the top pager row.

    Some background on what we're doing:  We have a checkbox that determines whether or not to display the total result count.  That result count, when displayed, is supposed to be in the left corner of the pager while the pager buttons and controls are right-justified.

    The default template in our skin looked like this:

        <PagerTemplate>
            <asp:Panel runat="server" id="countPanel" HorizontalAlign="left" CssClass="paginationDiv" style="float: left;" Visible="false">
            <asp:Literal runat="server" ID="countString"/>
            </asp:Panel>        
            <asp:Panel runat="server" id="pagerPanel" HorizontalAlign="right" CssClass="paginationDiv" style="float: right;">        
            <asp:ImageButton ID="firstPButton" runat="server" ImageUrl="~/images/icoRWEnd.gif" CommandArgument="First" CommandName="Page"/>
            <asp:ImageButton ID="prevPButton" runat="server" ImageUrl="~/images/icoRWOne.gif" CommandArgument="Prev" CommandName="Page"/>
            <asp:Literal runat="server" ID="pagerString" /> 
            <asp:ImageButton ID="nextPButton" runat="server" ImageUrl="~/images/icoFFOne.gif" CommandArgument="Next" CommandName="Page" />
            <asp:ImageButton ID="lastPButton" runat="server" Visible="false" ImageUrl="~/images/icoFFEnd.gif" CommandArgument="Last" CommandName="Page"/>
            </asp:Panel>
        </PagerTemplate>
    

    Panels used for grouping and float-left and float-right styles to achieve the visual effect

    Our GridView has a DataBound event handler that fills in and/or hides the countString and pagerString panels (the DataBound event presumably because that's the earliest point when we know the answers).

    When I found that the viewstate error was happening on the countPanel, I tried setting countPanel.EnableViewState = false; in the DataBound handler but that didn't stop the problem.

    I added EnableViewState = false  to the template on the contentPanel, and that *did* stop the problem.

    So is the DataBound handler running at the wrong place in the life cycle to impact the viewstate correctly?

    http://msdn.microsoft.com/en-us/library/ms972976.aspx discusses the page lifecycle vis a vis viewstate but the specifics of when Gridview events happen in there isn't immediately clear.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 8, 2014 6:36 PM
  • User1562156107 posted

    Okay, this was weird...

    If you set the pager row.ID in the DataBound event then the pager gets very brittle and unreliable.

    Our old code only expected 1 pager row (implicitly disallowed PagerSettings.Position == TopAndBottom) and set the ID of the row in an InitializePagerRow() override.  You don't want 2 html items with the same id, but InitializePagerRow() doesn't give you any straight-up sign which row you're working on at the moment, and TopPagerRow/BottomPagerRow aren't initialized yet.  

    So I moved the id setting to the DataBound event handler where we were filling in the pager text...

    I noticed that even our pages that *weren't* trying to implement on-the-fly pagesize changing had the pager broken and I started backing out things a bit at a time until I found it was setting the row id that was making everything nuts.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, December 12, 2014 3:15 PM

All replies

  • User2008642861 posted

    Hi mmodrall,

    Based on your post, I made a test on my computer, but it worked fine. It's hard to provide any suggestion with the information provided.

    I suggest that you can press F12 to debug , and check if your page has any error message or details.

    Or you could refer to the below link.

    http://blogs.msdn.com/b/asiatech/archive/2011/10/25/why-we-get-the-exception-failed-to-load-viewstate.aspx

    http://forums.asp.net/t/1295517.aspx

    If you have any other concern about it, please feel free to let me know.

    Best regards,

    Archer Wang

    Sunday, December 7, 2014 9:27 PM
  • User1562156107 posted

    Hi Archer...

    Thank you for taking the time to respond...

    I've read the 2 links, and the only controls that would be getting added/removed dynamically that I can think of would be the pager row controls.  The thing that puzzles me is that changing *other* fields would have the same effect, but those queries don't result in viewstate load errors.  

    For example, checking/unchecking the Show Count checkbox would result in those display controls appearing or not.  Changing the First or Last Name filter would result in different pager controls (when the new search only produces a single page of results, say).  But those changes don't result in a viewstate load error.

    I did attach the debugger, and the exception I see is deep in the ASP.Net bowels with a failure to cast an ArrayList to a Pair.  But with all the context optimized away, it's hard to get much context on which viewstate element it's trying to load.  It's about 15 levels deep in LoadViewStateRecursive from our master page.

    The actual formatting of our pager string is done in the DataBound event of the GridView; not sure if that's the right place to do it, but there we're not dynamically adding/removing controls; we check if the pager controls are present, and if they are we set the visible or not based on the configuration.

    If you put together a quick sample, I would appreciate seeing it, if that's not a problem for you.

    Thanks

    Mark

    Monday, December 8, 2014 12:14 PM
  • User1562156107 posted

    I've been playing with it a lot more today and am still not quite there on getting the behavior, but I did find that the viewstate exception was happening trying to read a Panel in the top pager row.

    Some background on what we're doing:  We have a checkbox that determines whether or not to display the total result count.  That result count, when displayed, is supposed to be in the left corner of the pager while the pager buttons and controls are right-justified.

    The default template in our skin looked like this:

        <PagerTemplate>
            <asp:Panel runat="server" id="countPanel" HorizontalAlign="left" CssClass="paginationDiv" style="float: left;" Visible="false">
            <asp:Literal runat="server" ID="countString"/>
            </asp:Panel>        
            <asp:Panel runat="server" id="pagerPanel" HorizontalAlign="right" CssClass="paginationDiv" style="float: right;">        
            <asp:ImageButton ID="firstPButton" runat="server" ImageUrl="~/images/icoRWEnd.gif" CommandArgument="First" CommandName="Page"/>
            <asp:ImageButton ID="prevPButton" runat="server" ImageUrl="~/images/icoRWOne.gif" CommandArgument="Prev" CommandName="Page"/>
            <asp:Literal runat="server" ID="pagerString" /> 
            <asp:ImageButton ID="nextPButton" runat="server" ImageUrl="~/images/icoFFOne.gif" CommandArgument="Next" CommandName="Page" />
            <asp:ImageButton ID="lastPButton" runat="server" Visible="false" ImageUrl="~/images/icoFFEnd.gif" CommandArgument="Last" CommandName="Page"/>
            </asp:Panel>
        </PagerTemplate>
    

    Panels used for grouping and float-left and float-right styles to achieve the visual effect

    Our GridView has a DataBound event handler that fills in and/or hides the countString and pagerString panels (the DataBound event presumably because that's the earliest point when we know the answers).

    When I found that the viewstate error was happening on the countPanel, I tried setting countPanel.EnableViewState = false; in the DataBound handler but that didn't stop the problem.

    I added EnableViewState = false  to the template on the contentPanel, and that *did* stop the problem.

    So is the DataBound handler running at the wrong place in the life cycle to impact the viewstate correctly?

    http://msdn.microsoft.com/en-us/library/ms972976.aspx discusses the page lifecycle vis a vis viewstate but the specifics of when Gridview events happen in there isn't immediately clear.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 8, 2014 6:36 PM
  • User1562156107 posted

    Okay, this was weird...

    If you set the pager row.ID in the DataBound event then the pager gets very brittle and unreliable.

    Our old code only expected 1 pager row (implicitly disallowed PagerSettings.Position == TopAndBottom) and set the ID of the row in an InitializePagerRow() override.  You don't want 2 html items with the same id, but InitializePagerRow() doesn't give you any straight-up sign which row you're working on at the moment, and TopPagerRow/BottomPagerRow aren't initialized yet.  

    So I moved the id setting to the DataBound event handler where we were filling in the pager text...

    I noticed that even our pages that *weren't* trying to implement on-the-fly pagesize changing had the pager broken and I started backing out things a bit at a time until I found it was setting the row id that was making everything nuts.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, December 12, 2014 3:15 PM