views:

711

answers:

5

I have a GridView in a ListView contained in a ScrollViewer element.

I understand WPF draws only the visible data at runtime, for example on scrolling grids only the visible rows are drawn initially - my problem is that I don't have as much power as on the desktop on a portable device I am developing for, so my WPF ListView - which scrolls ok on my desktop - is extremely slow on the portable device, which makes the page unusable (I only have a smt like 15 hidden rows).

Is there any dirty hack I can use to walk around the issue (such as scroll all the way down then back all the way up as soon as page loads or similar)?

Any other hacky ideas? Am I doing something wrong?

Any help appreciated!

EDIT: No matter how small the number of rows is (a few hidden rows, 3-4) the app gets stuck for a while as soon as I try to scroll.

EDIT: this is my XAML (removed styles for clarity):

<ScrollViewer Name="scrollViewer" Grid.Row="1">
        <ScrollViewer.Resources>
                <sys:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">60</sys:Double>
        </ScrollViewer.Resources>
        <ListView Name="recordContainer" Grid.Row="1" VirtualizingStackPanel.IsVirtualizing="False" ItemsSource="{Binding RecordCollection}">
            <ListView.View>
                <GridView>
                  <GridViewColumn Header="field1" DisplayMemberBinding="{Binding myField_1}"/>
                  <GridViewColumn Header="field2" DisplayMemberBinding="{Binding myField_2}"/>
                </GridView>
            </ListView.View>
        </ListView>
</ScrollViewer>
A: 

I'm not sure it will solve the problem, but you could try using a VirtualizingPanel

Thomas Levesque
thanks for the contribution - any pointers wrt how to use it and why it should solve?
JohnIdol
A VirtualizingPanel will not create more UI elements that it can display. So if your ListView has 10000 items, and only 10 are visible at a time, there will be only 10 UI elements created, which will be reused as you scroll. Currently there is only one implementation of VirtualizingPanel in the framework : VirtualizingStackPanel
Thomas Levesque
what I am trying to achieve is to create all the elements on load so that when the user scrolls they are already there (I am willing to sacrifice overhead on page load) ... which sounds like the opposite?
JohnIdol
But you never need to create more elements than what can be displayed at the same time. When you scroll, the same elements will be reused, and their content will be updated
Thomas Levesque
cannot use a VirtualizingStackPanel as I need my items to display as a grid (I am using a listView with a number of columns right now)
JohnIdol
OK, indeed it won't help if you're using a GridView... You should have a look at the DataGrid control (available in the WPF Toolkit, will be included in 4.0), I *think* it handles virtualization
Thomas Levesque
will check that out - thanks for pointing it out. At the moment I am in serious need of a dirty hack to get around this issue :)
JohnIdol
A: 

Hey John.

If you need to create elements on load and do not let Virtualizing panel create them as users scrolls through the list, then you should simply set the VirtualizingStackPanel.IsVirtualizing property to false:

<ListView VirtualizingStackPanel.IsVirtualizing="False">
</ListView>

As for DataGrid vs ListView performance. We found rendering time of the first one unacceptable on our project and decided to write our own grid control based on ListView. Performance difference was tremendous: from avg. DataGrid's 300ms we gained ~80ms from ListView...

Anvaka
This sounds very promising but for some reason I cannot notice much difference. Still works fine on a desktop but when moved to a less powerful device I would expect to take more to load the page then allow to scroll normally. Instead it's taking more or less the same time to load the page and when I hit the scrollbar it gets stuck for a while then allows me to scroll after a few seconds. Once I am all the way down if I try to scroll-up it gets stuck again but once I am back up I am able to scroll fluidly... any clue?
JohnIdol
Can you share the code? Also you could try ScrollViewer.IsDeferredScrollingEnabled="True" if this behavior suits your needs.
Anvaka
Edited the question to include xaml. I tried you trick withthe deferred scrolling and it is slightly better but still the first couple of times I scroll it refreshes after seconds (at least doesn't scatter), then it gets better (as it was happening before). I tried to remove the wrapping ScrollViewer to see if it was involved in the problem but even with the ListView Scrollbars the behavior doesn't change, so it's definitely not the ScrollViewer
JohnIdol
John, let me throw another dozen of questions on you. Maybe one of them will be the question that'll help you. How many elements do you have in your list? What templates does they have? What functionality from ListView is required? How does regular ListBox with hardcoded N items perform on your device? If you generate elements by yourself, from code behind, does it work faster? Are there any chance to profile your application on device to spot bottlenecks?
Anvaka
about 20 elements in a GridView within the Listview (no other templates). If I dynamically genrate the elements instead of databinding them it's slightly faster. If I profile the app looks like it's maxing out on CPU, but at this stage I am not sure if the bottleneck is the CPU or the hardware acceleration tat's not working (in dxdiag.exe AGP texture Acceleration comes up as not supported, while DirectDraw and Direct3D are enabled).
JohnIdol
A: 

Avoid setting the ScrollbarVisibility property to "Auto", that can degrade performance. Instead set it to "Visible", "Disabled", or "Hidden" (in your case probably "Visible").

Botz3000
Which element are you referring to? Is ScrollbarVisibility set to auto by default? I don't think I am explicitly setting it anywhere
JohnIdol
for the ScrollViewer, VerticalScrollbarVisibility property is set to visible - horizontal is disabled
JohnIdol
+2  A: 

The first thing I need to point out is that WPF renders using DirectX. If DirectX is not available, then the system automatically defaults to a software renderer (which is much slower).

Now, if DirectX is available (which is true in all full-blown computers, but not so on 'portable devices') the next problem you have is your graphics card's (or chip's) power.

I bring this up because you mentioned that your code uses styles on a portable device (that I'm assuming is not a laptop). If so, operations that are a piece of cake on a desktop computer might be extremely slow on your portable device.

Now, are your styles complex? or do they have a lot of render work? (i.e: complex gradients). If so, perhaps you could consider reducing (or eliminating) them from the application when it is being executed on your portable device.

WPF provides a nice way to determine if the hardware in which the software is being executed is capable of handling the load.

The code would be:

int RenderTier = (RenderCapability.Tier >> 16);

Now, if RenderTier == 0 then you have a video card (or chip) that cannot provide any kind of hardware acceleration, so all rendering wil be done using the WPF software renderer (on the CPU).

If RenderTier == 1, then you have partial acceleration. Some operations will be done on the graphics card, other on the CPU

if RenderTier == 2, you have full hardware acceleration, all rendering will be executed on the graphics card.

Kiranu
it's coming up with == 1 - Partial. The dxdiag.exe shows DirectDraw and Direct3D as enabled though (only AGP Texture acceleration is not supported by the device). I am profiling the slow operations and it seems like it's maxing out on CPU. Is it safe to assume the CPU is the bottleneck (meaning that even with AGP Texture acceleration enabled I wouldn't notice much of a difference)?
JohnIdol
It is probably safe to assume that. Your scrolling operations are probably that slow because of the hardware you are running your app on. My suggestion would be to reduce the amount of graphics used (perhaps on a machine dependant basis using the RenderTier). The maxing out of the CPU is explained because WPF is rendering using the software renderer, and CPUs are awful for rendering tasks (when compared with graphic cards)
Kiranu
yep but I am not too sure WPF is using software rendering since Direct3D seems to be working fine from tests on dxdiag.exe - only AGP Texture Acceleration is not supported, and what is that anyways? I am not using any graphics - I am just scrolling a grid :)
JohnIdol
Sorry for taking so long to answer, I was away... What happens is that _everything_ (text, buttons, boxes, etc.) in a WPF window is rendered using DirectX, I don't know if AGP Texture Acceleration is used for something, but it seems that your device is not suited for some of WPF's graphics operations.
Kiranu