Animating controls in C# - c#

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.

Related

See elements outside of the main form in C# Forms?

I'm a little bit frustrated with forms and feel like there have to be some features that I do not know yet (I'm still new to this). Currently I want to toggle two panels on button click, and have one panel move out on the left while the other moves in on the right. I can get it working somehow, but I'm losing so much time because I can only work on the panel that I see and have to keep dragging the panel that is out of the main form into the main form in order to see it and work on it.
Is there a way to also draw elements that are technically out of the draw range?
The panels should have transparent background and the main form background should not move , so moving in another form does not look like a viable option.

Using CacheMode From Worker Thread

I'm working with a WPF Canvas that contains a lot of elements. It needs to be able to pan and zoom. WPF cannot handle the layout of the canvas since it has too many elements (I don't know how many, but the XAML file is above 20mb).
The canvas is zoomed and panned using scale and translate transforms on the canvas' rendertransform.
A good trick I found is to use CacheMode. This fixes all panning problems as I generate a cache for the zoom level and set that. Easy, like this:
canvas.CacheMode = new BitmapCache(scale);
The problem is that I need to do it every time the scale changes (which is when the user zooms).
I understand that it will take some time to render the canvas and that is probably unavoidable. But how do I move that rendering to another thread so that it doesn't block the whole UI?
I understand the concept of Background Workers and Dispatcher and such, but I'm not sure how to handle this when the task that actually takes up all the time is the setting of a property that I can only access in the UI thread.
Is it possible to somehow generate the cache in another thread and then transfer it to the UI somehow?
Any other good ideas on how to lessen impact on the UI?

Updating the background of a hidden Windows Forms control

I have a Windows Forms control (a subclass of Panel) that serves as a panel that displays an image. The background of the control serves as the image that is displayed to the user.
The image itself is generally a screenshot of whatever is behind the application. The method of obtaining this screenshot is to hide the application and have the user press a button.
When that button is pressed, the screenshot is saved as the background of the Windows Forms control, and then the application is shown again. The background doesn't appear to update
until the control is visible again, and this causes a noticeable flicker of sorts as the old background switches to the new background. Is there a way to cause the background to
change while the control is hidden and remove this flicker?
Code:
public void updateBackground()
{
Image bg = null;
do
{
// this just gets the background using gdi32 and user32 calls
bg = Utilities.getDesktopImage();
}
while (bg == null);
// this function invokes the GUI thread to change the BackgroundImage of the
// drawPanel
drawPanel.setBackground(bg)
// drawPanel is a child control to the main Form
mainForm.show();
}
I have also tried using various forms of Refresh() and Invalidate() to get the control to update before it is shown. Application.DoEvents() seems to improve the speed, but there is still a noticible change from the old background to the new one.
Is there something that I'm missing? I can't seem to find what I'm looking for on Google, or elsewhere on StackOverflow.
Thanks.
Try moving your logic to another thread (Task, Backgroundworker or ThreadPool). This shall remove the lag you see.
The flicker occurs because (I assume) you do some relatively lengthy work in the UI thread, which blocks graphic message loop and everything "freeze" for a fraction of a second.
Are you using Win7 or Vista and is the Desktop Window Manager Service running?
Does the problem go away when the DWM is disabled (Control Panel --> Administrative Tools --> Services --> Desktop Window Manager Session Manager)?
It sounds like an issue with Aero - the way the DWM works is that the form's graphics buffer is not updated while it is hidden. The DWM stores the data from the last visible paint and doesn't refresh until the form is visible again. This causes the previous form canvas to be visible briefly until Windows gets around to repainting the changes since it was last visible (ie: the flicker).
This article discusses some of the topics :
http://blogs.msdn.com/b/greg_schechter/archive/2006/05/02/588934.aspx
There is probably a way to override some of this behaviour but I'm not familiar with it off the top of my head. Tagging this with GDI+ may help get better answers.

Create Animated Button

I have button it possible create animate on click?
with photoshop i have created a two image (enabled and disabled). Insert the picturebox in Windows Forms and Click event..Click the image changes from enabled to disabled, but you can have an animation?
Like this:
It looks like you mentioned WinForms so I'll address that. Yes animation is possible but in general it's going to be a bit of work.
There appears to be an implementation of a general purpose animation framework (although limited) over on CodeProject. In the comments schallos posted a better implementation of the reflection code using expression trees.
The general principle is:
Use a PictureBox so you get double buffering
Use a timer control to control repainting (calling Invalidate() on your PictureBox)
You'll probably want to add some easing into the animation so it appears smoother; a bit of acceleration added to it when the user clicks goes a long way.
A timer is not required using a GIF.
Using windows forms you could start by creating an animated GIF for each button. It would have to include both the forward and backwards direction. You can do this through Photoshop via the "Animation" panel. On the PictureBox click event you can set the image to play or stop.
The code below would set your image on the beginning frame.
imgButtonDimension = new FrameDimension(imgButtonDimension.FrameDimensionsList[0]);
imgButton.SelectActiveFrame(imgButtonDimension, 0);
pictureBox.Image = imgButton;`
If this is the approach you'd like to take I can provide further elaboration.

C# Only refresh PictureBox/Panel when tell them to refresh?

I'm making a bomberman game in a C# windows form application. It has over 300 pictureboxes (walls) that are placed on a panel. The picturebox of bomberman himself is also on that panel.
When the location of bombermans picturebox changes, all the controls on the panel are automatically refreshed. Because there are so many controls on that panel, and because the location of the picturebox changes multiple times per second, the program becomes laggy when I try to move.
I want to have control over the refresh event of the panel (and it's controls), because I think my problem is solved when only the pictureboxes that need to be refreshed, are refreshed programmatically.
I hope someone can help me out with this!
Ruud.
If you move the child, the parent has to be refreshed because it may need to draw the area where child was located previously. It would also mean that all children (of parent) would get refreshed.
OTH, using so many controls may not be a good idea. I would suggest you to keep data structures describing walls and then use it to draw it within Panel (or your custom control). You can write your own logic for hit testing (mouse or keyboard click within wall boundary) by capturing mouse/keyboard events at Panel/Parent level. With correct organization data structure, hit testing can be very efficient.
You are trying to paint the whole form which will surely take time . If you want to change only a part of the form, which in your case is Moving the bomberman to a new position, Only invalidate the area you want to repaint and then pass it to the Invalidate method.
Do something similar to this.
//Invalidate previous position of bomberman
Rectangle invalid = new Rectangle(picturebox1.Location.x,picturebox1.Location.y,picturebox1.Width,picturebox1.Height);
Invalidate(invalid);
//Add code to move your picture box and then call above two lines again
invalid = new Rectangle(picturebox1.Location.x,picturebox1.Location.y,picturebox1.Width,picturebox1.Height);
Invalidate(invalid);
Note sure but somthing similar polished code would work...
Here is a link to an example for reference. http://msdn.microsoft.com/en-us/library/ms229628.aspx

Categories