none
Retain Scroll Position

    Question

  • I have made a custom control that is responsible for displaying and allowing edits to a collection of data objects. This custom control consists of a panel with its autoscroll property set. For every object in the collection I add another custom control to the panel. This allows for a nice scrolling through the collection.

    Certain events occur however, where I need to rebuild the control. When I rebuild I repeat the process of going through the data objects in the collection and creating a new control, adding it to the panel.

    What has resulted is that when an event fires it scrolls back to the top. Some users might get annoyed with that. Does anyone have ideas on retaining the scroll position when rebuilding the control?



    I see there are ScrollOffset and ScrollPosition properties. What is the difference between the two? How does the Point the property returns relate to the scroll position? What are the units?

    If I could save the state of the scroll, rebuild, and then set it back that might be OK, unless the number of elements has changed.
    Wednesday, March 17, 2010 4:22 PM

Answers

  • I did some redesign where I didn't have to rebuild the control, but I did find there is a property AutoScrollPosition, which you can grab, do work, then have to negate and set again. It worked well. Although you can see objects getting added, the scroll button shrinking and moving to the top and then moving itself back down when there are alot of controls to scroll through.

     

    Friday, March 19, 2010 5:29 PM

All replies

  • Hi Christopher,

    It is not clear to me your current design. But I have some suggestions to remember current scroll and scroll to a particular position.

    First, you can access Panel.VerticalScroll.Value and Panel.HorizontalScroll.Value to get current position of the vScrollBar and hScrollBar of Panel. Set these two properties can set scrollbar position.

    When I test the case on my Win7 computer, I found an interesting thing.
    For example:
    You click a button to set scrollbar position with following code.
    panel1.VerticalScroll.Value = 10;
    panel1.HorizontalScroll.Value = 50;
    The content on the panel does move but the scrollbar’s position doesn’t change. Call Refresh method doesn’t help. Then I double the code.
    panel1.VerticalScroll.Value = 10;
    panel1.VerticalScroll.Value = 10;
    panel1.HorizontalScroll.Value = 50;
    panel1.HorizontalScroll.Value = 50;

    Everything works properly. I think this is the defect of Panel control. I have not tested it on other OS. If you experience the same, please use my solution to work around it.

    If you have any problems, please feel free to tell me.

    Sincerely,
    Kira Qian
    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework!
    Thursday, March 18, 2010 2:44 AM
  • Hi Christopher,

    I often had to deal with that problem when I use DataGridView to display data.
    My approach is pretty simple and straight forward:

    1. store the ID of the currently selected row in the DataGridView (get the ID from the underlying DataRow object)
    2. reload data
    3. search the data to find the position of a row with the stored ID (with a for loop over the DataTable.DefaultView)
    4. tell the grid to scroll to that position (if it was found).

    This eliminates the problem of how many rows were reloaded. It selects and scrolls into view previously selected row in the grid.

    I believe the same principle could be applied to your case.
    It would mean that you track which UserControl (representing your data object) was selected the last. Each UserControl would have to store the data object ID, or better yet, have a reference to the data object it represents. 
    So if you know the ID of the data object that you need to scroll to, when you reload data, in the process of populating user controls, all you need is to store a reference to the user control representing that object.
    Then when you're done call Panel.ScrollControlIntoView method to scroll to that user control and give focus to it.
    Or you can get the desired location using ScrollableControl.ScrollToControl and then calculate the scroll values and scroll the panel manually using Panel.VerticalScroll.Value and Panel.HorizontalScroll.Value like Kira suggested.


    Hope this helps ...
    Best regards,
    Vladimir


    Thursday, March 18, 2010 9:39 AM
  • I did some redesign where I didn't have to rebuild the control, but I did find there is a property AutoScrollPosition, which you can grab, do work, then have to negate and set again. It worked well. Although you can see objects getting added, the scroll button shrinking and moving to the top and then moving itself back down when there are alot of controls to scroll through.

     

    Friday, March 19, 2010 5:29 PM