I ran into a little problem while writing Windows 8 application on C#+xaml. My app has one main page, which is divided in two parts – ListView as a navigation panel on the left, and Frame on the right. All of that looks and works a bit like PC Settings panel. But there is one difference – when page into frame has enough content and it’s scrollable, I perform animation of collapsing navigation panel to icons-only state (when in full width it has text and icons).
So, here is the problem. Let’s say I’m on the first page and panel is collapsed. Then I go to the second page, and I've got to return to full-width state of panel. But since I’m doing it at the same time as showing content in the frame, there is a little freeze of animation, and it's becoming really noticeable when GridView has got a lot of items. So animation freezes on a half way, then GridView render all items images, and then it continue.
Only way to fix this problem I come up with, is to do navigation after animation completed. It’s doesn’t look very pretty, so I go on a blank page first, perform animation, and then go on target page. But this solution still feels wrong, and there still some problems with animation after resume from suspending.
So, is there any way to ensure that rendering of GridView will not interfere with my animation?
Thank you, and sorry for my English.
You can set NavigationCacheMode on the pages to Required and navigate through all the pages to preload them while hiding the Frame using the Opacity property, but that will be slow the first time you do it. Try to limit the number of bitmap pixels you need to decode and render on each page too. If all else fails - see if the Preload() method of the AlternativeFrame control from WinRT XAML Toolkit might be of help.
Related
Here's the scenario:
I've got a series of many views primarily containing listboxes. Listboxes, some with large amounts of data in them, some with very little.
Currently, I've got an attached behaviour that essentially just detects when new content has been loaded into the container for these views (a ContentPresenter) and triggers a simple XAML storyboard that offsets the container by 200px to the left, or to the right, and also lowers the opacity to 0% (at 0ms) then over 100ms it restores the opacity to 100% and reduces the offset back to 0px, creating a 'sliding into view' sort of effect.
Now, the issue:
The framerate of this animation varies horribly anywhere from a smooth transition to jittery, to outright just lagging at 1 frame until completion.
This is almost certainly due to the fact it's having to load the new view, render everything in it, then even further; lists with loads of data in them need even more render time, THEN whilst all that's happening it's trying to animate its location changing which seems to drastically affect the performance of the animation.
it shocks me that something as simple as moving some pixels across the screen is so graphically intensive for WPF to handle
Here's a crude representation of the animation itself:
My question:
Is there any sort of fundamental best-practice for dealing with intensive animations in WPF so as to improve their performance, or any kinds of small changes to things that when added up boost performance?
Or is WPF just terrible at animating and we just have to deal with it.
I think your problem is, that you try to do everything at the same time or same thread. Just try to do it async in splitted tasks. There are plenty of different approaches to that. Another approach would be to just handle the work with a semaphore, this should push your performance a bit up.
I've come up with a solution which, in my case, has always solved the jitter problem. It is certainly worth trying. The strategy is to take any element that will not change throughout the animation, insert it in a local reference framework such as a grid or canvas, make that grid or canvas store cached versions of its content, and then apply your animation to the grid or canvas, rather than the inside elements. It is as simple as this:
<Canvas ...Your canvas properties...>
<Canvas.CacheMode>
<BitmapCache />
</Canvas.CacheMode>
...Your UI elements...
</Canvas>
or, for a grid:
<Grid ...Your grid properties...>
<Grid.CacheMode>
<BitmapCache />
</Grid.CacheMode>
...Your UI elements...
</Grid>
You'll want to simply ensure that you do not update anything inside the canvas (or grid), as this will undo the cached version and you'll find yourself with a similar issue where WPF will regenerate its rendering on every frame.
By having cached versions of the content, what WPF will be moving across the screen is not a dynamically updated element, it is simply a bitmap of the last render of that element, and WPF will update that bitmap only if changes are applied to the element.
If that does not solve your issues, it means that performance is hindered by something occurring outside the generation of the local element. This means you'll want to look at your overall application, or reduce the entire frame rate of your application. However, in virtually all cases of jittering and jerky movements I found for my WPF animations, the BitmapCache solution seems to work all the time. Just be careful in not applying animations to objects inside the element being cached.
Rendering a Viewport3D with a RenderTargetBitmap.Render call seems to cause the Viewport3D to no longer update its visual content. The interactive actions still work though, such a hover-over and clicking.
I've created an example in which I have a viewport which contains a button. I then render the viewport with RenderTargetBitmap. After this render, I try to toggle the visibility of the button but the visuals of the button no longer update which is unexpected. It is however not possible to click on the button as you would expect when it is collapsed. Toggling back the visibility to visible allows me to click the button again so it seems that only the visuals are no longer processed correctly.
It seems that the viewport loses track of the correct buffer it should use and keeps displaying the old version no matter what. I would like the viewport to just keep updating its visuals as it did before the render call, any ideas what I am missing here?
I've uploaded the demonstrator on bitbucket, the sourcefiles can be viewed here:
Sourcecode
The demonstrator is also available as a VS2010 solution:
download solution
If you require any other information please let me know, I'll try to answer your questions as detailed as possible.
I was having a similar issue. After the call to RenderTargetBitmap's Render(), I noticed that, for example, any color changes applied to the visuals within the Viewport were not being displayed. As you state, the interactive actions like clicking, rotating, hover-over, etc. were still working.
Within my application the Viewport being rendered was itself sitting inside (i.e. a child of) a Grid. I found that if, after the call to RenderTargetBitmap's Render() method, I removed the Viewport from and then readded the Viewport to the Grid's 'Children' list, the visuals within the Viewport continued to update as they did before the call to Render().
I have been trying to find out how to redraw a view when i have zoomed in on it, i have looked at many examples (mainly native code) but am still struggling to get it fully working.
So let me try and explain what i am attempting....
I have a UIScrollView With a UIView(container) in it this in turn has many views within it each with UITextFields inside, the functionality i am looking for is when a user clicks on any of the view it is zoomed in on and then goes back into place when the user is finished with it which does all actually work fine except for the quality of the zoomed in view is terrible.
I am using a UIScrollViewDelegate but not really sure what to put in the ZoomedEnded function to handle the redraw, I have tried using the CATiledLayer but am not really sure how this is used and i always just end up with a black screen.
There is not much code to show as
svCertScroller.SetZoomScale(2.34f, true);
Works fine and in the UIScrollDelegate event ViewForZoomingInScrollView just returns the view i want zoom in on but i don't have anything in ZoomingEnded event at the moment I have tried loads but nothing even seems to get close.
So any help on what to put inside this event to sharpen up the zoomed in view would be great.
Thanks in advance.
Make the scroll canvas larger and plot the contents at a higher resolution.
I have a form with a TableLayoutPanel docked to it, and with a TextBox, Image, TreeView and ListView within that Panel.
When the user resizes the form, these controls resize with it, but there is a noticeable delay if the user resizes quickly or if the user maximizes the entire form; the delay is so considerable that I was able to screenshot it:
You can also notice that the "Options" button is displayed twice, once where it should be (on the upper right-hand corner) and once in the middle of the search box (where it was before the form resized). This isn't supposed to happen, but is also caused by the delay.
Shortly after this screenshot was taken, the form looked fine, but does anyone know of a way to eliminate or reduce this delay?
I edited the image for privacy reasons, but there were only 60 or so items in the listview.
Do you have any special code handling the redrawing?
If so are you using the BeginUpdate() method and the EndUpdate() method?
From msdn:
Prevents the control from drawing until the EndUpdate method is called.
These methods (depending on your situation) could cause the components not to be updated until after the resize has occurred. This might stop the items appearing twice on the screen and speed up the resize.
Maybe you have virtual items in your listview, and your items are recalculating slowly? Do you have any code that is running when listview need redraw?
I'm trying to get scrollbars working with the web browser control. However, as I'll be using it to display a message for a custom messagebox, I don't want the scrollbar to appear even if its not needed - as it seems to do by default. To circumvent this I decided to disable scrollbars on the control and instead use scrollbars on another control like a Panel. This way they'll only appear when the contents of the browser page is too big to fit.
This hasn't worked out too well, though I've read quite a few posts, even on StackOverflow, where this seems to be a valid solution. One example is when I tried using the solution here:
Scrolling problem with a WebBrowser control contained in a Panel control
It seems as though if Scrollbars are disabled for the web browser, it won't let the panel use scrollbars either. This seemed to be the case when testing in design mode. To overcome this I tried adding a picture box behind the web browser inside the panel; it worked when in design mode (resizing the picture box and web browser would cause the panel to enable its scrollbars), but didn't work during runtime (I added code to have the picture box change to the size of the web browser control - which itself is always resized to fit the size of the scrollable contents).
I also tried programmatically enabling and disabling the web browser's scrollbars based on if the ScrollableRectangle size was bigger than the size of the control. This theoretically would be fine, except it seems to clear all text within the control any time the ScrollbarsEnabled property is changed - and thus is changed back to having no scrollbars.
I'm doing this with the following code, called effectively whenever a key is pressed in the control:
if (Output.Document.Body != null)
{
if (Output.Document.Body.ScrollRectangle.Size.Height > Output.Size.Height
|| Output.Document.Body.ScrollRectangle.Size.Width > Output.Size.Width)
Output.ScrollBarsEnabled = true;
else
Output.ScrollBarsEnabled = false;
}
else
Output.ScrollBarsEnabled = false;
It's also important to note that I also need a solution for the HTML editor which will be used within the app, so ideally any solution would not rely on a page load event etc... as these do not seem to trigger when the web browser has design mode set to on (which is needed for it to work as an HTML editor). However, in this particular situation I can fall back on enabling the default scrollbars if there's no better solution.
EDIT: To be clear, I am not talking about any scrollbars within the HTML content - that is of no concern as the HTML is simply being used to allow for flexible formatting of text. I'm talking only about the scrollbar of the browser control itself.
Any help much appreciated. Thanks!
I ended up finding a solution to this some time ago now, but forgot to post here. Basically what I did was first enable the scrollbars by default so they will work, although always appear. Then I created a panel control and sized it over the top of the inactive scrollbar that appears on the right of the web browser control.
Next I changed the anchors of the scroll bar panel so that the top, bottom, and right sides would always snap into the size of the form, and hence the size of the browser control as all edges of it too are anchored.
Then I added some code that checked the ScrollRectangle size and compared it with that of the browser, if it turned out to be larger in height or width, I then made the cover panel not visible, but otherwise left it in place.
Here's the relevant code snippets:
//If still bigger, set scrollbars:
if ((Output.Document.Body.ScrollRectangle.Size.Height > Output.Size.Height) ||
Output.Document.Body.ScrollRectangle.Size.Width > Output.Size.Width)
{
ScrollPanel.Visible = false;
ScrollPanel.Enabled = false;
}
Hope this helps someone else in future, took a few different methods before I found one that worked well enough.
I've decided to up Sheng's answer (when I get enough reputation) as, firstly he was the only person to response, and secondly, his information helped me when I was contemplating the use of some kind of invocation to try and enable the scrollbars during runtime. Though I found my solution simpler and just as effective.
That's too late. IDocHostUIHandler.GetHostInfo is called when the webbrowser is created, and the WebBrowser's implementation sets DOCHOSTUIFLAG_SCROLL_NO or the DOCHOSTUIFLAG_FLAT_SCROLLBAR flag based on the value of its ScrollBarsEnabled property.
I suggest you to set ScrollBarsEnabled to false before creating the Webbrowser control's window.
If you don't want the scrollbar of a particular element, such as body, div or textarea, to appear, you can set their styles to overflow='hidden' or use scrolling properties specific to the elements such as doc.Body.SetAttribute("scroll","no").