PictureBox 效能與縮放控制不足,採用自繪 OnPaint。發現 Graphics.DrawImage 僅顯示 GIF 第一幀。解決方案:System.Drawing.ImageAnimator。
| 方法/屬性 | 用途 |
|---|---|
CanAnimate(Image) | 判斷圖片是否為動畫(多幀) |
Animate(Image, EventHandler) | 開始播放,每幀觸發回呼 |
StopAnimate(Image, EventHandler) | 停止播放 |
Image.SelectActiveFrame(FrameDimension, index) | 切換當前顯示幀 |
Image.GetFrameCount(FrameDimension) | 取得總幀數 |
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace GifTest {
public class AnimateImage {
private readonly Image _image;
private readonly FrameDimension _dimension;
private readonly int _frameCount;
private int _currentFrame;
private bool _playing;
public event EventHandler OnFrameChanged;
public Image Image => _image;
public bool CanAnimate { get; }
public int FrameCount => _frameCount;
public int CurrentFrame => _currentFrame;
public bool IsPlaying => _playing;
public AnimateImage(Image img) {
_image = img;
lock (_image) {
CanAnimate = ImageAnimator.CanAnimate(_image);
if (CanAnimate) {
var guid = _image.FrameDimensionsList[0];
_dimension = new FrameDimension(guid);
_frameCount = _image.GetFrameCount(_dimension);
} else {
_frameCount = 1;
}
}
}
public void Play() {
if (!CanAnimate || _playing) return;
lock (_image) {
ImageAnimator.Animate(_image, OnFrameChangedHandler);
_playing = true;
}
}
public void Stop() {
if (!CanAnimate || !_playing) return;
lock (_image) {
ImageAnimator.StopAnimate(_image, OnFrameChangedHandler);
_playing = false;
}
}
public void Reset() {
Stop();
lock (_image) {
_image.SelectActiveFrame(_dimension, 0);
_currentFrame = 0;
}
}
private void OnFrameChangedHandler(object sender, EventArgs e) {
lock (_image) {
_currentFrame = (_currentFrame + 1) % _frameCount;
_image.SelectActiveFrame(_dimension, _currentFrame);
}
OnFrameChanged?.Invoke(this, e);
}
}
}
_image 的操作皆在 lock(_image) 內,ImageAnimator 回呼執行緒與 UI 執行緒並發存取(current + 1) % count 實現循環播放OnFrameChanged 通知 UI Invalidate() 觸發重繪Image 生命週期,AnimateImage 不擁有PictureBox 內部使用 ImageAnimator 但不暴露控制介面請參考「C# WinForms GIF 動畫繪製完整實戰(二)」:雙緩衝設定、OnPaint 鎖定繪製、播放/停止/重置按鈕綁定。