Maintain scroll position in listboxes in updatepan

2019-01-14 09:04发布

问题:

I have a listbox inside an update panel. When I scroll down and select an item, it scrolls back to the top of the listbox. I heard that the dom does not keep track of the scroll position on a postback. Does anyone have a solution/example on how to solve this?

Thanks, XaiSoft

回答1:

You're running into this problem because the UpdatePanel completely replaces your scrolled <select> element with a new one when the asynchronous request comes back.

Possible solutions:

  1. Use JavaScript to store the scrollTop property of the <select> element in a hidden form element before the UpdatePanel is submitted (by calling the ClientScriptManager.RegisterOnSubmitStatement method) and then setting it on the new <select> when the AJAX call comes back. This will be tedious, error-prone, and probably not very compatible (see here).

  2. Use JavaScript to store the <select>'s selectedIndex property and re-select that item when the AJAX call comes back. Obviously this won't work if the user hasn't selected anything yet.

  3. Don't use UpdatePanels. Try jQuery + ASP.NET page methods instead.



回答2:

    var xPos, yPos;
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    function BeginRequestHandler(sender, args) {
        if (($get('Panel1')) != null) {
            xPos = $get('Panel1').scrollLeft;
            yPos = $get('Panel1').scrollTop;
        }
    }

    function EndRequestHandler(sender, args) {
        if (($get('Panel1')) != null) {
            $get('Panel1').scrollLeft = xPos;
            $get('Panel1').scrollTop = yPos;
        }
    }
    prm.add_beginRequest(BeginRequestHandler);
    prm.add_endRequest(EndRequestHandler);

    //Note: "Panel1" Panel or div u want to maintain scroll position
    //Note: This Java Script should be added after Scriptmanager*****

//Maintain Scroll Position for Panel/Div with out Update panel

    window.onload = function() {
        var strCook = document.cookie;
        if (strCook.indexOf("!~") != 0) {
            var intS = strCook.indexOf("!~");
            var intE = strCook.indexOf("~!");
            var strPos = strCook.substring(intS + 2, intE);
            document.getElementById('Panel1').scrollTop = strPos;
        }
    }
    function SetDivPosition() {
        var intY = document.getElementById('Panel1').scrollTop;
        document.title = intY;
        document.cookie = "yPos=!~" + intY + "~!";
    }


   //Note: "Panel1" Panel id or div id for which u want to maintain scroll position


回答3:

It seems that the following code example scrolls in the following way:

  • Internet Explorer 8: After postback the selected item is the first visible item.

  • Firefox: After postback the selected item is always visible (but might be the last visible item).

  • Chrome: After postback, the selected item might be hidden since the listbox scrolls to the top, as you say.

<asp:UpdatePanel ID="up1" runat="server">
    <ContentTemplate>
        <asp:ListBox ID="lb1" runat="server" Height="100px" AutoPostBack="true">
            <asp:ListItem>A</asp:ListItem>
            <asp:ListItem>B</asp:ListItem>
            <asp:ListItem>C</asp:ListItem>
            <asp:ListItem>D</asp:ListItem>
            <asp:ListItem>E</asp:ListItem>
            <asp:ListItem>F</asp:ListItem>
            <asp:ListItem>G</asp:ListItem>
            <asp:ListItem>H</asp:ListItem>
        </asp:ListBox>
    </ContentTemplate>
</asp:UpdatePanel>


回答4:

You can still achieve the partial postback using the UpdatePanel containing a ListBox, but prevent it from being overwritten by a new instance by setting the following on the UpdatePanel:

ChildrenAsTriggers="False"

This as stated in the MSDN:

Gets or sets a value that indicates whether postbacks from immediate child controls of an UpdatePanel control update the panel's content. Set the ChildrenAsTriggers property to false if do NOT you want postbacks from immediate child controls of the UpdatePanel control to cause an update of the panel's content.

The one caveat to this is if you are trying to do any other visual manipulation to the ListBox from the server-side (i.e. adding CSS attributes to the items on postbacks), then you will not see them render until another unrelated postback occurs. If all you are doing is making selections than setting ChildrenAsTriggers="False" will work.



回答5:

For the enterprise application I was working on, it turned out that the MasterPage.Master page was handling the Sys.WebForms.PageRequestManager.getInstance().add_endRequest event and setting window.scroll(0,0) within it. The content pages were obviously executing the window.scroll(0,0) on each trigger of the contentpage's UpdatePanel. I tried overriding the add_endRequest functionality in the content page but could not get that to work. Eventually I just modified the Master.Master to not do window.scroll(0,0).