I have created an animation that takes 400 milliseconds to run, and attached it to an EventTrigger for the Loaded RoutedEvent of my Window.
But I think the window doesn't show up right away after it's loaded*, so I can't see the animation at all.
What are some common patterns for running animations when a Window loads?
And also, when should I run animations in separate threads?
* It probably draws the window after it is loaded and it shows the window after it's finished drawing, clarification would be helpful.
400 Miliseconds is pretty fast, so a loading window can take longer. I'd suggest keeping it in the same thread, but using a timer event.Timer Interval to delay it until the window is fully loaded.
I use the time events for splash screens, etc... and would do the same, I am sure, for a timed animation. It just takes a little practice. My suggestion is to use a long delay on the time to make sure it acts the way you want... then reduce the timer to put it where you want in the load screen.
I have tried the solutions suggested in the following answer:
https://stackoverflow.com/a/8886941/494094
Window.ContentRendered
UIElement.LayoutUpdated
Window.Activated
So far, Window.Activated event seems to suit me best. The only caveat is that none of those events are RoutedEvents, so you need to define the animation in the code behind like the following:
this.Activated += (sender, args) => ((Storyboard) FindResource("MyAnimation")).Begin();
Related
I have an winforms application with two controls in which I do custom drawing. The main control shows a small section of a long continuous image of a road, while the other control shows a horizontally-squashed representation of the entire road image. The second control is used to navigate the first: you can click anywhere in the overview to scroll to that location in the main view. Here's a screenshot, where the main view is on top and the overview is on bottom:
There's a cyan line in the overview control that indicates the position of the imagery being shown in the main view. (In this screenshot, it's just over 1/3 the width from the left.) The user can click and drag that line in the overview, which will cause the main view to scroll.
I've noticed something odd about the redrawing: When I'm dragging the cyan line in the overview control, the main view gets redrawn much more often than the overview, even though both are invalidated in response to the mouse move. I know that WM_PAINT messages only get sent when there are no other messages in the queue, but I don't understand why one control would get redrawn more often than the other if they're both being invalidated at the same time.
Actually, as I was typing that last sentence I think I stumbled on the reason. Tell me if this sounds right:
Each control has its own message queue, and the main control isn't receiving any input-related messages, so its message queue is empty more often than that of the overview, which has to process all the mouse events. So it receives the WM_PAINT message more often than the overview.
So at this point, I guess the question is, "Does that make sense? Is that what's happening?"
The theory is not sound, there is only one message queue per thread. What you see is almost certainly caused by the way WM_PAINT is generated. It is only delivered when the queue is empty. That makes it a "low priority" message, user input always goes first. Important that it works that way, you would not want user input to get lost, or the message queue to explode, because painting code is slow.
So, roughly, you called Invalidate() twice. The bottom-most window gets the Paint event but by the time it is finished there is yet another mouse event waiting to be processed. So the second window does not get its paint event and you'll invalidate a window that is already invalidated. Only when you slow down the mouse, or stop moving it, can it catch up.
Easy to see from Task Manager, you'll see the UI thread of your program burning 100% core.
Forcing a paint anyway is possible, but you have to call Update() instead of Invalidate(). Your program still burns 100% core but now instead of skipping paints it will be less responsive to the mouse. That sounds dangerous, with the potential to flood the message queue, but it is not. WM_MOUSEMOVE does not get added to the message queue either. Like WM_PAINT, it only gets generated when the queue is empty. You'll get it first.
I'm trying to slide a control to the right when I move the cursor on that control and slide back when the cursor is out.
Since the form contains many control with the same animation, I've decided to let those control slide on different threads. The problem is, when I create a thread and use Control.Invoke() to change the location of the control, the main UI freezes until the animation is completed.
What am I doing wrong? Or is there any way to work around?
Edit: Also used Control.BeginInvoke(). The result is the same.
That happens when you try to move the control faster than UI thread can handle. The below library is a good example of how to do animations with a SINGLE global FRAME-LIMITED timer for all animations.
WinForm Animation Library [.Net3.5+]
A simple library for animating controls/values in .Net WinForm (.Net
3.5 and later). Key frame (Path) based and fully customizable.
https://falahati.github.io/WinFormAnimation/
new Animator2D(
new Path2D(c_control.Location.X, c_control.Location.Y, c_control.Location.X + 100, c_control.Location.Y, 250))
.Play(c_control, Animator2D.KnownProperties.Location);
This moves the c_control control 100 pixels to the right in 250ms.
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.
I have a form with 2 controls on it. Control 1 has several search criteria and the user can click a button to start the search. Control 2 has a GridView that will display the search results and also has a PictureBox with an animated Gif in it.
Control 1 has a method in it that has a nested foreach loop that takes upwards of 5 minutes to complete (depends upon the search criteria, sometimes it finishes almost instantly).
What happens is that I call a method on Control 2 that makes the PictureBox visible and the animated Gif starts running. As soon as the foreach loop is hit that takes a while, the image completely stops. Whenever I show any MessageBoxes the image starts running again (I presume it is because the MessageBox is blocking). As soon as the MessageBox is closed, the image stops animating.
I presume I will need to utilize something with threading, but everything I am trying (ImageAnimator, Thread calling a method that calls Invoke, etc.) all seem to not work. Any hints what events/libraries I need to work with in order to make this work? Any good examples to follow?
You long running code runs in the GUI-Thread and blocks the internal message loop, so any GUI is stopping. Try to run your long running code in a separate worker thread.
2 words: BackgroundWorker class.
http://msdn.microsoft.com/en-us/library/waw3xexc.aspx
I am currently creating a custom control that needs to handle animation in a C# project. It is basically a listbox that contains a fixed number of elements that are subject to move. An element (another user control with a background image and a couple of generated labels) can move upwards, downwards or be taken out of the list.
I would like to create animated movement as the elements get moved around within the container custom control but it seems to me that moving controls around using lines such as
myCustomControl.left -= m_iSpeed;
triggered within a timer event is flickery and has a terrible rendering, even with double buffering turned on.
So here's the question : What is the best way to achieve a flicker-free animated C# control? Should I just not create custom controls and handle all of the drawing within a panel's background image that I generate? Is there a super animation method that I have not discovered? :)
Thanks!
your best bet for flicker-free animation is to do the painting yourself (use the Graphics object in the Paint event handler) and use double-buffering. In your custom control you will need code like this in the constructor:
this.SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor,
true);
A similar discussion took place this morning on this question. visual c# form update results in flickering. so I will be lazy and give the same answer I gave there:
You could try to call this.SuspendLayout(); before you start your move and this.ResumeLayout(false); when you have finished moving all of the controls. In this way all controls should draw at once and you should have less of a flicker.
On a side note I have tried to reproduce this here at work, but seem to be failing. Can you give some more sample code that I can fix maybe?
See How to double buffer .NET controls on a form.
The normal way to get flicker-free animation is to implement double-buffering. Take a look at this Code Project article
http://www.codeproject.com/KB/GDI-plus/flickerFreeDrawing.aspx
Minimizing calls to paint until you are ready is also a good idea.