There are a lot of topics about different drawing approaches in WPF. Starting from Shapes and Polygons, ending with low-weight DrawingVisual and BitmapCache.
However, when it comes to frequent redrawing, say, moving line once per 16 ms (equal to 60 times per second), it appears to be choppy. And none of these approaches seems to provide required update frequency and smooth movement.
So the question is, how can it be achieved?
NOTE: I came up with this question after describing my issue in details in another topic: How to achieve smooth UI updates every 16 ms?
Solution was found. Using CompositionTarget.Render is the way to go!
http://msdn.microsoft.com/en-us/library/ms748838%28v=vs.110%29.aspx
Related
I have been trying to find out specific ways of improving the load times of a treeview element that contains 1500 flat nodes. At the moment it takes over 15 seconds to expand a single node.
I have tried the suggestions regarding virtualisation but its my understanding that virtualisation basically avoids loading and rendering elements that cannot be seen. Correct?
If so, what happens when you expand an element where there are 1500 items within that single expansion, does it not then need to load those 1500 items?
It seems obviously, if I split up my TreeView so that each time 10 elements were added, it added another folder. So you couldn't view the whole treeview at once. This is NOT really an option for me.
So is there a way of possibly background loading the tree element add, so that I can display the treeview even while its loading items?
This is the only solution I can think of but I have yet to come across a way of being able to update the UI and not be blocking at the same time.
Thanks
Virtualization is the logical way to go.
Math is your friend here:
Let's, for the sake of argument, assume that 1 node takes up an insanely small 5 vertical pixels. A screen with a height of 7500 pixels would be able to show all 1500 nodes.
Cutting the number in half to 750 nodes would still require a height of 3750 pixels.
If we take a more reasonable height for one node, I think the default is 19, a decent 4K monitor would be able to show around 200 of them.
I'm currently running on a 1920x1200 monitor, with scaling at 100% (strangely called "smaller"). Explorer, with the ribbon collapsed, shows me 43 items. 2000 pixels would give me around 73 items in view. And the items in Explorer are pretty much as small as I would want them to be without going blind.
Bottom line: You're unlikely to run in to the problems with virtualization.
For anybody coming across this question. Ensure you haven't wrapped (or even have a scrollviewer) in the same grid as your treeview.
It completely disables virtualisation without warning.
I currently work in a customer assignment related to performance problems in a WPF rich client LOB application.
The problem is that the application runs very slow/sluggish. Especially data table handling (scrolling, sorting, selection) is extremely slow and leaves the application unusable.
I analyzed the system state when a single tab containing a few textboxes, comboboxes and labels is opened and left idle (waiting for user input).
These are my findings:
All the rendering is calculated on the GPU
There are no performance heavy features such as animations, bitmap effects, transparency, etc.
When the tab is idle (only the cursor is blinking in the focused textbox, the rest of the tab is static and does not even contain any data) the GPU runs up to 90%
GPU drops to 0 whenever the tab loses focus
GPU percentage directly relates to the window size. A small window brings it down to a few percent, full screen makes it go up to almost 100%
WPF Perforator tells me that WPF calculates the dirty region for the entire tab instead of only the blinking cursor
WPF Perforator reports dirty rect update rates larger than 20/sec on the idle tab and they directly correlate to GPU usage
My conclusion:
During development a lot of custom code (layout, event handling, etc..) has been introduced in order to fit WPF to the backend-driven architecture of the system as a whole. My guess is that due to some of the custom code the dirty-rect-mechanism of WPF has been broken. This leads to too much drawing activity and thus very high GPU usage. These innecessary activities lead to the problems described above.
Now I am looking for any advice where I should start my investigation. Or in other words: What are typical mistakes that a developer can make in order to break the WPF dirty-rect update algorithm. Any input is highly appreciated.
Many thanks and best regards!
Manuel
Thanks for the input. Let me clarify backend-driven: The UI is highly dynamic. A message from the backend defines the structure of the ui and the data to be displayed. Therefore, we do not have any xaml for the structure of the tabs, only c#.
In the meantime, I could solve the problem. I used Snoop and collapsed every element one by one while monitoring GPU usage. I found out that there was a very tiny pixelshader effect (DropShadowEffect) on one of the borders. As soon as I removed the effect, the GPU dropped from 80% to 1%. WPF drew correct dirty rectangles over small portions of the UI. Problem solved, case closed.
Things that seem interesting to me:
1. The tremendous impact that this small effect has on the GPU usage.
2. That it breaks the dirty-rect calculation.
3. Since it was not a BitmapEffect but a PixelshaderEffect I could not reveal it by disabling BitmapEffects in Perforator.
Thanks!
MM
I've been playing around with Silverlight 5 and started putting together a little game. It's nothing special and it's purely to just play around.
If you look at the link below you'll notice that it's lagging a bit.
Link(Just use the arrow keys): http://www.netauto.co.za/WIP/GameTest.html
Basically I'm using a Storyboard to scroll the road and move the cars on the screen with every tick. At first I used the CompositionTarget.Rendering, but I was having the same problem. So I thought I'll try a Storyboard, but it made no difference.
There is a second timer that adds a vehicle in a random lane with every tick. They get removed once they go off screen. Disabling this timer makes no difference.
CPU usage is almost none. Also tried it on another PC and it was exactly the same.
I would post some code, but there's quite a bit of it and as I'm just fooling around it's a bit of a mess 0.o
Any ideas on how I can move the objects around without that lag?
I'm using Silverlight 5.
Thank you
You can try to use BitmapCache on the scrolling road and cars, if you are not already. This can cut down on the traffic to the GPU.
More links: One, Two.
I have a few fairly simple animations (moving text around, moving ellipses etc.) and running in full screen (1920x1080 minus the task bar) the WPF Performance Suite reports a good framerate around 50 FPS throughout the animation. Dirty Rect Addition is somewhere around 300 rect/s, the SW frames are between 0 and 4 and the HW frames are between 3 and 5. Video memory usage is around 80 MB.
Problem is that the animations stutters every other half second. It is definitely not fluid :-(
My machine is a new Dell laptop XPS 15 with the GeForce GT 435 with 2GB memory. - The drivers are up to date. (The same behavior occurs on my netbook (in full screen) as well so I don't think it is hardware related.)
If I make the window smaller the stutter goes away.
The stutter occurs with the simplest of animations - even with just a couple of elements but adding more elements certainly makes it more noticeable.
How can I find out what causes this stutter?
When I think of it, I have not actually seen any WPF animations which run smoothly in full screen. Is this even possible?
Have you tried to set a lower "max frame rate" to the animation?
<Storyboard Timeline.DesiredFrameRate="10">
<!-- ....blah blah blah -->
</Storyboard>
If your animation is causing massive recalculation of child or parent elements, changing the DesiredFrameRate will have a cascading effect on the number of calculations made by the system.
Also, check out the "Remarks" section of this link. It explains why/when you should use it.
If setting a lower frame rate fixes your stuttering, then you need to consider simplifying your XAML to limit the amount of recalculation needed at every frame of your animation (limiting the number of child or parent objects resized - or affected in any way - by every frames/changes made by the animation.
You might want to also check out the "WPF Performance Suite". It is an awesome set of tools to determine what exactly is going on in your WPF app, seeing which parts of your window are being repainted and when, and the CPU usage of each of your XAML elements!
Hope this helps!
Patrick,
I have no answers. All I can do is provide some solidarity. I'm trying to animate an ItemsControl. The concept is pretty simple, really. I've got a ListView and in the ListView I have a GridView. I want the items in the GridView to to smoothly go from one row to another row as the underlying list is sorted so that, for example, a sorted list will stay sorted as the values in the list change.
I've noticed this: animation on moderately complex controls is a CPU hog. The stuttering I'm pretty sure is simply related to the CPU being maxed out (I noticed you didn't provide the CPU graph on your dump above). Keep the CPU around 50% and the animation appears smooth, above 75% and you get these stutters.
Still working on the problem, but I think it goes deeper than my code.
Don
I had a similar issue where it was stuttering, nothing really major it just looked like little stutters here and there while I ran the program. On a hunch, I shut down Google Chrome while it was running and that fixed it,the scrolling became completely smooth...
So my advice would be if you have any internet browsers open check to see if closing them out fixes the problem.
I have a WPF application with many tabs..
in one tab.. i make a verycomplex vector drawing consisting of thousands of drawing visuals.. (this represents a machine and all elements need to be interactable..)
It takes 3/4 seconds for drawing this for the first time..After the first draw it should be done..
The problem is if i switch to another tab and comeback, it takes atlease 2,3 seconds to show the tabpage with drawing again.. Since there is no redraw, why should it take so much time..?
If the component is not going to change, you could call Freeze() on it to mark it as done. Without trying it out I don't know if that would help, but you could give it a shot.
Not all objects are Freezable. Check out the MSDN documentation for more info:
http://msdn.microsoft.com/en-us/library/ms750509.aspx
Another thing you could try would be rendering the vector art to a bitmap, and displaying that. Maybe it makes you feel icky to lose the vector precision, but if you know it's not going to change and it will look the same, what's the harm? (If you support printing or something that will require a hi-res version, you could always switch back for that operation.) For info on how to convert a UIElement to a bitmap, check out:
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap.aspx
Another possible solution: You don't really explain what kind of interaction you are doing with the elements, but if all you want to do is zoom and pan, a RenderTransform may be good enough (which is more efficient than a LayoutTransform and/or moving all the elements individually). I haven't played around with combining Freeze() and a RenderTransform, but you may be able to get the desired zooming while reducing the amount of layout WPF has to do.