我第一次使用ImageAnimator对象,发现对StopAnimate()的调用似乎并没有真正停止底层线程的运行和调用FrameChanged处理程序。
我已经创建了一个测试来说明这一点,我想知道是否有有ImageAnimator经验的人可以解释一下StopAnimate()方法实际上应该做什么。MSDN说它应该停止动画,但它没有。
我意识到我可以使用bool来控制何时处理更新,但他的方法是一种变通方法,并使(如果有效的话) StopAnimate()方法变得多余。
以下是一些测试代码,不需要外部资源:
using System;
using System.IO;
using System.Threading;
using System.Drawing;
namespace ImageAnimatorDemo
{
class Program
{
static void Main(string[] args)
{
AnimateGif();
}
private static void AnimateGif()
{
Image testImage = null;
using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(GifData)))
{
testImage = Image.FromStream(stream);
}
ImageAnimator.Animate(testImage, delegate(object o, EventArgs args)
{
// Each time the frame is updated this will fire
Console.WriteLine("Tick");
});
Thread.Sleep(750);
// The following code should stop the "animation" for the supplied image which I would
// THINK would stop the frame changed callback from firing...
Console.WriteLine("Stop requested, should not see more \"Ticks\"...");
ImageAnimator.StopAnimate(testImage, delegate(object o, EventArgs args)
{
Console.WriteLine("Stopped");
});
Console.ReadLine();
}
private static string GifData =
"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";
}
}
发布于 2011-07-14 02:38:40
我反编译了这个类,发现ImageAnimator启动了线程工作程序:
/// <devdoc>
/// Worker thread procedure which implements the main animation loop.
/// NOTE: This is the ONLY code the worker thread executes, keeping it in one method helps better understand
/// any synchronization issues.
/// WARNING: Also, this is the only place where ImageInfo objects (not the contained image object) are modified,
/// so no access synchronization is required to modify them.
/// </devdoc>
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
static void AnimateImages50ms() {
Debug.Assert(imageInfoList != null, "Null images list");
while( true ) {
// Acquire reader-lock to access imageInfoList, elemens in the list can be modified w/o needing a writer-lock.
// Observe that we don't need to check if the thread is waiting or a writer lock here since the thread this
// method runs in never acquires a writer lock.
rwImgListLock.AcquireReaderLock(Timeout.Infinite);
try {
for (int i=0;i < imageInfoList.Count; i++) {
ImageInfo imageInfo = imageInfoList[i];
// Frame delay is measured in 1/100ths of a second. This thread
// sleeps for 50 ms = 5/100ths of a second between frame updates,
// so we increase the frame delay count 5/100ths of a second
// at a time.
//
imageInfo.FrameTimer += 5;
if (imageInfo.FrameTimer >= imageInfo.FrameDelay(imageInfo.Frame)) {
imageInfo.FrameTimer = 0;
if (imageInfo.Frame + 1 < imageInfo.FrameCount) {
imageInfo.Frame++;
}
else {
imageInfo.Frame = 0;
}
if( imageInfo.FrameDirty ){
anyFrameDirty = true;
}
}
}
}
finally {
rwImgListLock.ReleaseReaderLock();
}
Thread.Sleep(50);
}
}
一旦它启动了,看起来没有任何方法可以让它停止,实际上是相当糟糕的。
发布于 2015-01-18 08:13:32
我遇到了一个问题,带有动画gif图像的PictureBox控件会导致应用程序退出时挂起。
罪魁祸首是在while(true)循环中创建线程的静态ImageAnimator类。
幸运的是,ImageAnimator将使用的线程设置为私有字段。它可以通过反射访问并中止,也可以停止动画。
这是我的代码,我已经确认中止线程,动画停止。
try
{
var type = typeof(ImageAnimator);
var info = type.GetField("animationThread", BindingFlags.NonPublic | BindingFlags.Static);
if (info != null)
{
var value = info.GetValue(null);
var thread = value as Thread;
if (thread != null && thread.IsAlive)
{
thread.Abort();
}
}
}
catch{}
发布于 2019-03-15 06:14:55
您的代理没有被取消订阅的原因是因为ImageAnimator
正在将代理地址与您最初订阅的代理地址进行比较。传递给StopAnimate
的委托与传递给Animate
的委托不同。
这是StopAnimate
中的相关代码块
try {
// Find the corresponding reference and remove it
for(int i = 0; i < imageInfoList.Count; i++) {
ImageInfo imageInfo = imageInfoList[i];
if(image == imageInfo.Image) {
if((onFrameChangedHandler == imageInfo.FrameChangedHandler) || (onFrameChangedHandler != null && onFrameChangedHandler.Equals(imageInfo.FrameChangedHandler))) {
imageInfoList.Remove(imageInfo);
}
break;
}
}
}
请注意onFrameChangedHandler
的比较。
ImageAnimator
使用单线程,因此您的应用程序中的所有动画图像都可以由单个线程进行动画处理。如果你杀死了工作线程,你的应用程序中的所有动画图像都将停止动画。如果您只有一个,这可能是很好的,但在大多数情况下可能不是您想要的。
Animate
和StopAnimate
工作得很好;您只需要正确地调用它们。
https://stackoverflow.com/questions/6012646
复制相似问题