ImageAnimator.StopAnimate()似乎实际上没有做任何事情

|| 我第一次使用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 =
            \"R0lGODlhEAAQAPQAAP///wAAAPDw8IqKiuDg4EZGRnp6egAAAFhYWCQkJKysrL6+vhQUFJycnAQEBDY2Nmh\" +
            \"oaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAw\" +
            \"EAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFdyAgAgIJIeWoA\" +
            \"kRCCMdBkKtIHIngyMKsErPBYbADpkSCwhDmQCBethRB6Vj4kFCkQPG4IlWDgrNRIwnO4UKBXDufzQvDMaoS\" +
            \"DBgFb886MiQadgNABAokfCwzBA8LCg0Egl8jAggGAA1kBIA1BAYzlyILczULC2UhACH5BAkKAAAALAAAAAA\" +
            \"QABAAAAV2ICACAmlAZTmOREEIyUEQjLKKxPHADhEvqxlgcGgkGI1DYSVAIAWMx+lwSKkICJ0QsHi9RgKBwn\" +
            \"VTiRQQgwF4I4UFDQQEwi6/3YSGWRRmjhEETAJfIgMFCnAKM0KDV4EEEAQLiF18TAYNXDaSe3x6mjidN1s3I\" +
            \"QAh+QQJCgAAACwAAAAAEAAQAAAFeCAgAgLZDGU5jgRECEUiCI+yioSDwDJyLKsXoHFQxBSHAoAAFBhqtMJg\" +
            \"8DgQBgfrEsJAEAg4YhZIEiwgKtHiMBgtpg3wbUZXGO7kOb1MUKRFMysCChAoggJCIg0GC2aNe4gqQldfL4l\" +
            \"/Ag1AXySJgn5LcoE3QXI3IQAh+QQJCgAAACwAAAAAEAAQAAAFdiAgAgLZNGU5joQhCEjxIssqEo8bC9BRjy\" +
            \"9Ag7GILQ4QEoE0gBAEBcOpcBA0DoxSK/e8LRIHn+i1cK0IyKdg0VAoljYIg+GgnRrwVS/8IAkICyosBIQpB\" +
            \"AMoKy9dImxPhS+GKkFrkX+TigtLlIyKXUF+NjagNiEAIfkECQoAAAAsAAAAABAAEAAABWwgIAICaRhlOY4E\" +
            \"IgjH8R7LKhKHGwsMvb4AAy3WODBIBBKCsYA9TjuhDNDKEVSERezQEL0WrhXucRUQGuik7bFlngzqVW9LMl9\" +
            \"XWvLdjFaJtDFqZ1cEZUB0dUgvL3dgP4WJZn4jkomWNpSTIyEAIfkECQoAAAAsAAAAABAAEAAABX4gIAICuS\" +
            \"xlOY6CIgiD8RrEKgqGOwxwUrMlAoSwIzAGpJpgoSDAGifDY5kopBYDlEpAQBwevxfBtRIUGi8xwWkDNBCIw\" +
            \"mC9Vq0aiQQDQuK+VgQPDXV9hCJjBwcFYU5pLwwHXQcMKSmNLQcIAExlbH8JBwttaX0ABAcNbWVbKyEAIfkE\" +
            \"CQoAAAAsAAAAABAAEAAABXkgIAICSRBlOY7CIghN8zbEKsKoIjdFzZaEgUBHKChMJtRwcWpAWoWnifm6ESA\" +
            \"MhO8lQK0EEAV3rFopIBCEcGwDKAqPh4HUrY4ICHH1dSoTFgcHUiZjBhAJB2AHDykpKAwHAwdzf19KkASIPl\" +
            \"9cDgcnDkdtNwiMJCshACH5BAkKAAAALAAAAAAQABAAAAV3ICACAkkQZTmOAiosiyAoxCq+KPxCNVsSMRgBs\" +
            \"iClWrLTSWFoIQZHl6pleBh6suxKMIhlvzbAwkBWfFWrBQTxNLq2RG2yhSUkDs2b63AYDAoJXAcFRwADeAkJ\" +
            \"DX0AQCsEfAQMDAIPBz0rCgcxky0JRWE1AmwpKyEAIfkECQoAAAAsAAAAABAAEAAABXkgIAICKZzkqJ4nQZx\" +
            \"LqZKv4NqNLKK2/Q4Ek4lFXChsg5ypJjs1II3gEDUSRInEGYAw6B6zM4JhrDAtEosVkLUtHA7RHaHAGJQEjs\" +
            \"ODcEg0FBAFVgkQJQ1pAwcDDw8KcFtSInwJAowCCA6RIwqZAgkPNgVpWndjdyohACH5BAkKAAAALAAAAAAQA\" +
            \"BAAAAV5ICACAimc5KieLEuUKvm2xAKLqDCfC2GaO9eL0LABWTiBYmA06W6kHgvCqEJiAIJiu3gcvgUsscHU\" +
            \"ERm+kaCxyxa+zRPk0SgJEgfIvbAdIAQLCAYlCj4DBw0IBQsMCjIqBAcPAooCBg9pKgsJLwUFOhCZKyQDA3Y\" +
            \"qIQAh+QQJCgAAACwAAAAAEAAQAAAFdSAgAgIpnOSonmxbqiThCrJKEHFbo8JxDDOZYFFb+A41E4H4OhkOip\" +
            \"XwBElYITDAckFEOBgMQ3arkMkUBdxIUGZpEb7kaQBRlASPg0FQQHAbEEMGDSVEAA1QBhAED1E0NgwFAooCD\" +
            \"WljaQIQCE5qMHcNhCkjIQAh+QQJCgAAACwAAAAAEAAQAAAFeSAgAgIpnOSoLgxxvqgKLEcCC65KEAByKK8c\" +
            \"SpA4DAiHQ/DkKhGKh4ZCtCyZGo6F6iYYPAqFgYy02xkSaLEMV34tELyRYNEsCQyHlvWkGCzsPgMCEAY7Cg0\" +
            \"4Uk48LAsDhRA8MVQPEF0GAgqYYwSRlycNcWskCkApIyEAOwAAAAAAAAAAAA==\";
    }
}
    
已邀请:
我对该类进行了反编译,发现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);
        }
    }
一旦启动,它似乎没有停止的任何方式,实际上非常cr脚。     
我有一个问题,其中带有动画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{}
    
您的代表未取消订阅的原因是“ 3”正在将代表地址与您最初订阅的代表的地址进行比较。您传递给
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;
              }
          }
}
注意the8的比较。
ImageAnimator
使用单个线程,因此应用程序中的所有动画图像都可以由单个线程进行动画处理。如果您杀死工作线程,则应用中的所有动画图像都将停止动画处理。在大多数情况下,如果只有一个但可能不是您想要的,这可能很好。
Animate
StopAnimate
工作正常;您只需要正确调用它们即可。     

要回复问题请先登录注册