Virtualizing Very large Scrollviewer RRS feed

  • Question

  • My apologies in advance for this rather long post.

    I am working on a PDF viewer for Windows 8.1 Store apps. The viewer displays PDF pages inside a ScrollViewer. We've run into a fairly large obstacle with large documents, where it turns out that the ScrollViewer won't display anything below a certain VerticalOffset. There's a msdn thread about it here:http://social.msdn.microsoft.com/Forums/windowsapps/en-US/f0b2b401-57ec-4cf0-9092-8bed5194f62b/scrollviewer-does-not-render-content-at-offsets-larger-than-2096700?forum=winappswithcsharp#4eb5d5c1-3887-4e3c-af03-96c0f6a8a7b2

    I though it better to start a new thread, as I've accepted that I will have to do something about it myself.

    Basically, if a document has some 1000 pages or so, then content below the offset 2096700 gets cut off. (We do offer a single page view mode with a FlipView, but that's an option for the user, not a solution to the problem).

    As you can see in the thread, the suggestion is to virtualize the ScrollViewer.

    As far as I am concerned, we already are vitualizing it. The ScrollViewer contains a Canvas of a size calculated to contain every page of the document, but it's completely transparent. Instead, as the user scrolls around, only the content where the viewport current is is rendered, as well as some of the surrounding content (in order to facilitate smooth scrolling). Content too far from the ViewPort is removed.

    On a side note, this is how we originally built it for Windows 8.0, and it worked fine there. It's something that changed with the plumbing under the hood for Windows 8.1.

    I've been thinking about how to solve this problem, and come up with a few possible solutions. However, I am not convinced they're the best ones available. So I wanted to ask others what they suggest I do.

    One of the solutions I've thought of is to shrink the content of the ScrollViewer so that it's never larger than, say, 1000000. Then, when the user gets closer to the bottom of that, I can move back up to the top half and add all the content further up than it actually should be (basically, subtract 500000 from the offset). With zooming in and out, this might be somewhat tricky. The other problem now is of course the ScrollBars. I guess I would have to somehow add my own ScrollBars and make the ScrollViewer's two scrollbars invisible. Would this be doable?

    Other than this, I can't relly think of anything else that could be considered virtualization. Perhaps some of you have an idea of how to solve a problem like this, or perhaps you could tell me that my above suggestion is crazy...

    I also considered to leave the content of the ScrollViewer empty, and instead have my own content below (z level wise) that I can move about using RenderTransformations to match that of the ScrollViewer. I even ran a small experiment with colored rectangles, and found some issues which makes me thing it will be very hard to do. It seems that when the ScrollBar first pops up (Visibility auto) when you zoom in then the content jumps a bit. This might be solvable though...

    I guess it's also possible to develop my own control from scratch... Maybe base it off of something like PanView (http://code.msdn.microsoft.com/windowsapps/PanView-A-Metro-Panning-dc8f28c3) I am however worried that the manipulation won't feel right (physics working differently than regular ScrollViewer). Also, the manipulation code will be executed on the UI thread, which might lead to some lag as it's already a rather heavy control.

    Any other suggestions or ideas? I realize this is probably not a common problem.

    Thanks, Tomas

    Monday, July 7, 2014 8:04 PM

All replies

  • Hi,

    Would you mind sharing a reproduce sample in OneDrive and I don't have a large PDF file can test with it.  

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place. <br/> Click <a href="http://support.microsoft.com/common/survey.aspx?showpage=1&scid=sw%3Ben%3B3559&theme=tech"> HERE</a> to participate the survey.

    Wednesday, July 16, 2014 6:12 AM
  • Hi,

      >> Basically, if a document has some 1000 pages or so, then content below the offset 2096700 gets cut off.

    Let's think about the question a bit further, first of all, do we really need a ScrollViewer for the scenario that you described? From my experience, with 1000 pages, it is very difficult for a user to use a scroll bar to scroll to a particular location. In this context, the scroll bar is useful in scroll one or two pages, which can easily be replaced by, say, 2 buttons. If you don't need to support mouse and keyboard (you support touch only), scroll bars are even more useless. However per my understanding, the idea that limit the content to a small size is a good solution, and is actually required to avoid using too much memory, without a ScrollViewer, you can add some logic for the user to pan the screen using either mouse wheel or touching. You might also want to display some lightweight UI to indicate approximately where the user is, such as a thin slider representing reading progress. It would be better to hide the UI whenever possible, for example, if the user stops panning, after several seconds, you hide the UI and leave content only.

    Best Regards,

    Ming Xu

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, July 29, 2014 5:23 AM
  • Pardon the late response here, I just got back from Vacation.

    First of all, I am using the ScrollViewer because of the "correct" behaviour it provides with Panning and Zooming. Especially with touch interaction, it's important that the control Feels right. Microsoft provides a built in ScrollViewer which is used in many apps and therefore users are familiar with the touch and feel of it. I am not so much interested in ScrollBars. However, we don't know if the user is opening a 4 or 4000 page document, and in the case of 4 pages, the ScrollBar is quite useful. In both cases, we want the same behaviour in terms of look and feel.

    As in the post I referenced, I will again point to the PDF Reader that ships with Windows 8 and 8.1. I can open a 4000 page document in continuous page mode and when I scroll and zoom, the ScrollBar updates to reflect my position. Opening a large scrollable document is a valid use case and has been for over 25 years, so I'm not sure why this is now a problem in Windows 8.1. The design is fine and there is a genuine problem with the Windows 8.1 ScrollViewer. I am now in the position of having to work around the problem and I would appreciate some help in doing so.

    Basically, I want the behaviour that the built in Reader app has. The thing that I find quite annoying is that obviously, at some point, someone solved this problem. You built this app with a ScrollViewer (or similar enough control that it makes no difference) and it can handle offsets way larger than 2096700. But for some reason, it's not available to us developers. When we ask about it we get told that we should "think about our design" or whatever.

    -inventing the wheel and create my own ScrollViewer for this purpose. Apart from it likely taking quite a long time, I would also be worried about performance and physics.

    I've been told multiple time that I should Virtualize the ScrollViewer. In a sense I am already doing this, by only adding content to regions close to the current ViewPort and removing content that is too far away. The main content of the ScrollViewer is just a large, blank Canvas.

    So, is there any advice on how to proceed with this, in order to create something that looks and feels rather like the default Windows PDF Reader, using the ScrollViewer as a base for interaction and efficiency (both programmer time and processing time while running).


    Tomas Hofmann

    Tuesday, August 12, 2014 6:51 PM
  • Hi there, 

    Do you encounter memory pressure in your app with so many pages? It's better to consider virtualization solutions..  UI virtualization or data virtualization. given this situation.



    Thursday, August 14, 2014 6:21 AM
  • Hi Jenny,

    No, I do not experience memory pressure. We are using the same methodology for our iOS and Android Versions of the App. We also have a .net Version, and works just fine. We also had a perfectly fine solution in Windows 8.0, using exactly the same method. The app's memory usage is stable.

    I understand that a virtualizing solution is the way to go. Which is what this thread is all about.

    In fact, I have already implemented a virtualizing solution. Our solution is simple:

    1. Calculate the size needed to display the entire document.

    2. Create a Canvas control of that size, and set it as the child to the ScrollViewer.

    I hope at this point we can all agree that we're not using a whole lot of memory.

    3. Track the viewport position, and render the content corresponding to the current viewport (and surrounding areas for smooth panning). We don't even render entire pages, but chop it up to 300 x 300 tiles or so. So at any given time, only a small region surrounding the current viewport actually has any content. The rest is blank. Does this not qualify as virtualization?

    I can create a ScrollViewer, add a blank canvas with a height of 2200000, and put nothing except a small rectangle at the bottom of that canvas, and it will not show up. The program will be using less than 30 MB of memory. This is a bug/defect in the ScrollViewer, and I now find myself in the unpleasant position of having to work around it.

    Ideally, Microsoft would recognize this as a problem and fix it, but it seems that it has been decided that large, continuous scrolling is no longer a valid use case, even though it has been used for a long time and that it is currently working on all other platforms that we use.

    I have had to explain the situation several times, and am only ever told vaguely to go and virtualize the content. It is virtualized. It worked just fine in your previous version. But then the underlying mechanics changed and broke the ScrollViewer. And instead of acknowledging this and fixing the issue, I just get told that a very common use case is actually invalid, and to virtualize, which I'm already doing and when memory pressure is not the problem.

    I am not cramming the ScrollViewer full of content. I am using it as a base to handle user interaction (panning, scrolling, zooming, etc) which it is designed for. If I don't make the ScrollViewer's content large enough, then how can I expect interaction to work properly when I get to the bottom of a large document. How can I make the scrollbars reflect the actual position and behave like they do for the current ScrollViewer?

    Let's put it like this. You were creating the PDF reader that is built in to Windows 8.1. You wanted to support a continuous mode like it does, but you found out that for large documents you couldn't use the ScrollViewer. Taking away continuous mode was not an option. How would you go about it?


    Thursday, August 14, 2014 5:15 PM
  • Hi there,

    For this the how to problem, to better resolve your issue based on your app scenario, more research and code changing/tests are meeded acoordingly, it's better to submit a technical support ticket.



    Tuesday, August 19, 2014 8:22 AM