在wpf(C#)中读取gif文件时内存不足

时间:2015-10-13 14:22:03

标签: c# wpf c#-4.0 wpf-controls

我使用c#编写了一个控件读取gif文件,如下所示:

public class AnimatedGIFControl : System.Windows.Controls.Image
    {

    public static readonly DependencyProperty IsPlayProperty = DependencyProperty.Register("IsPlay", typeof(bool), typeof(AnimatedGIFControl), new UIPropertyMetadata(false, new PropertyChangedCallback(OnIsPlayChanged)));

    public bool IsPlay
    {
        get
        {
            return (bool)this.GetValue(IsPlayProperty); 
        }
        set
        {
            this.SetValue(IsPlayProperty, value);
        }
    }

    private static void OnIsPlayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if((bool)e.NewValue)
        {
            (d as AnimatedGIFControl).StartAnimate();
        }
        else
        {
            (d as AnimatedGIFControl).StopAnimate();
        }            
    }

    public static readonly DependencyProperty GifSourceProperty = DependencyProperty.Register("GifSource", typeof(string), typeof(AnimatedGIFControl), new UIPropertyMetadata(null, new PropertyChangedCallback(OnGifSourceChanged)));

    public string GifSource
    {
        get
        {
            return (string)this.GetValue(GifSourceProperty);
        }
        set
        {
            this.SetValue(GifSourceProperty, value);
        }
    }

    private static void OnGifSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as AnimatedGIFControl).AnimatedGIFControl_Loaded();
    }

    private Bitmap _bitmap; // Local bitmap member to cache image resource
    public delegate void FrameUpdatedEventHandler();


    /// <summary>
    /// Delete local bitmap resource
    /// Reference: http://msdn.microsoft.com/en-us/library/dd183539(VS.85).aspx
    /// </summary>
    [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool DeleteObject(IntPtr hObject);

    /// <summary>
    /// Override the OnInitialized method
    /// </summary>
    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        this.Unloaded += new RoutedEventHandler(AnimatedGIFControl_Unloaded);
    }

    /// <summary>
    /// Load the embedded image for the Image.Source
    /// </summary>       
    public void AnimatedGIFControl_Loaded()
    {
        _bitmap = new Bitmap(Application.GetResourceStream(new Uri(@"pack://application:,,,/" + this.GifSource)).Stream);
        Source = GetBitmapSource(_bitmap);
        if (this.IsPlay && _bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif))
        {
            StartAnimate();
        }
    }

    /// <summary>
    /// Close the FileStream to unlock the GIF file
    /// </summary>
    private void AnimatedGIFControl_Unloaded(object sender, RoutedEventArgs e)
    {
        StopAnimate();
    }

    /// <summary>
    /// Start animation
    /// </summary>
    public void StartAnimate()
    {
        ImageAnimator.Animate(_bitmap, OnFrameChanged);
    }

    /// <summary>
    /// Stop animation
    /// </summary>
    public void StopAnimate()
    {
        ImageAnimator.StopAnimate(_bitmap, OnFrameChanged);
    }

    /// <summary>
    /// Event handler for the frame changed
    /// </summary>
    private void OnFrameChanged(object sender, EventArgs e)
    {
        Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle,
                               new FrameUpdatedEventHandler(FrameUpdatedCallback));
    }

    private void FrameUpdatedCallback()
    {
        ImageAnimator.UpdateFrames();

        if (Source != null && Source.CanFreeze)
        {
            Source.Freeze();
        }                

        // Convert the bitmap to BitmapSource that can be display in WPF Visual Tree
        Source = GetBitmapSource(_bitmap);
        InvalidateVisual();            
    }

    private BitmapSource GetBitmapSource(Bitmap bitmap)
    {
        IntPtr handle = IntPtr.Zero;
        BitmapSource bitmapSource = null;

        try
        {
            handle = bitmap.GetHbitmap();
            bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
                handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            if (handle != IntPtr.Zero)
            {
                DeleteObject(handle);
            }
        }
        return bitmapSource;
    }

}

我在wpf中使用它如下:

<customControl:AnimatedGIFControl x:Name="faultImage" HorizontalAlignment="Center" VerticalAlignment="Center"
                              IsPlay="True"
                              GifSource="Images/RouteWindow/BigFaultReportImage.gif"/>

我让应用程序运行24小时,在1GB内存上升。 如果是因为我忘了清理记忆呢? 我不知道为什么。拜托,帮助我!

1 个答案:

答案 0 :(得分:1)

我认为问题是你在每次帧更新时创建一个位图而你永远不会调用垃圾收集器。你试过调用GC.Collect();在InvalidateVisual()之后; ?