So I have a custom Button class in a Winforms app written in C# 4.0. The button holds a static image normally, but when a refresh operation takes place it switches to an animated AJAX-style button. In order to animate the image I have a timer set up that advances the image animation on every tick and sets that as the button image. That's the only way I can get it to work. The solution I have isn't that efficient; any advice would be helpful.
So two questions: 1. Is there an easier way - as in am I overlooking some feature I should be using? 2. Is there a better way to manually animate the image?
Find code below of what I'm doing on each tick. The first area of improvement: maybe copy each frame of the image to a list? Note the _image.Dispose(); failing to dispose of a local Image was causing memory leaks.
Thanks for any advice here. I will post something online and link it 开发者_高级运维once I have an efficient solution.
private void TickImage()
{
if (!_stop)
{
_ticks++;
this.SuspendLayout();
Image = null;
if(_image != null)
_image.Dispose();
//Get the animated image from resources and the info
//required to grab a frame
_image = Resources.Progress16;
var dimension = new FrameDimension(_image.FrameDimensionsList[0]);
int frameCount = _image.GetFrameCount(dimension);
//Reset to zero if we're at the end of the image frames
if (_activeFrame >= frameCount)
{
_activeFrame = 0;
}
//Select the frame of the animated image we want to show
_image.SelectActiveFrame(dimension, _activeFrame);
//Assign our frame to the Image property of the button
Image = _image;
this.ResumeLayout();
_activeFrame++;
_ticks--;
}
}
- I guess Winforms is not so reach in animation capabilities on its own. If you want more advanced animation use may consider some third-party solutions.
- I think you should not load image from resource every tick. The better way is to preload image frames one and hold the reference. Then use it to set appropriate frame every tick.
As I've recently tested, animated gifs are animating well without any additional coding, at least on standard buttons. But if you still need to aminate frames manually, you may try something like this:
// put this somewhere in initialization
private void Init()
{
Image image = Resources.Progress16;
_dimension = new FrameDimension(image.FrameDimensionsList[0]);
_frameCount = image.GetFrameCount(_dimension);
image.SelectActiveFrame(_dimension, _activeFrame);
Image = image;
}
private void TickImage()
{
if (_stop) return;
// get next frame index
if (++_activeFrame >= _frameCount)
{
_activeFrame = 0;
}
// switch image frame
Image.SelectActiveFrame(_dimension, _activeFrame);
// force refresh (NOTE: check if it's really needed)
Invalidate();
}
Another option is to use ImageList
property with preloaded static frames and cycle ImageIndex
propery just as you do it with SelectActiveFrame
above.
精彩评论