2011-05-16 71 views
1

我第一次使用ImageAnimator对象,并发现对StopAnimate()的调用似乎并未实际停止运行底层线程,调用FrameChanged处理程序。ImageAnimator.StopAnimate()似乎没有实际执行任何操作

我已经创建了一个测试来说明这一点,我想知道是否任何具有ImageAnimator体验的人都可以对StopAnimate()方法实际应该做的事情有所了解。 MSDN表示它应该停止动画,但它不会。

我意识到我可以使用布尔来控制何时处理更新,但他是一种解决方法,并使(如果它的工作)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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"; 
    } 
} 

回答

2

我反编译的类,发现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); 
     } 
    } 

一旦开始它不看起来有什么办法可以阻止它,实际上很糟糕。

+0

小代码格式化,拼写错误和拼写错误也很有趣。我会认为MS会将所有的代码审查完毕并清理干净。我也不是讽刺。 – 2011-07-15 02:25:29

0

我有一个问题,其中带有动画gif图像的PictureBox控件会导致应用程序退出时挂起。

罪魁祸首是静态ImageAnimator类创建一个在while(true)循环中的线程。

幸运的是,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{}