我有一个 WindowsPhone 7.8 应用程序,它需要显示动画 GIF 以及 Silverlight 直接支持的图像。因此我们创建了一个自定义用户控件public sealed partial class ExtendedImageControl : UserControl, IDisposable
,它有一个名为 ImageSource 的 DependancyProperty。此属性绑定到 URL。然后,后面的代码会将常规的 Image 控件插入 LayoutRoot 或 AnimatedImage。但是,当 AnimatedImage 离开视图或包含页面关闭时,它不会释放其内存。
加载逻辑如下:
ExtendedImage loadedImage = (ExtendedImage)await Utils.Caching.Image.LoadCachedImageFromUrlAsync<ExtendedImage>(loadedLocation);
if (ImageSource == loadedLocation)
{
AnimatedImage image = new AnimatedImage();
image.Stretch = stretch;
image.Source = loadedImage;
LayoutRoot.Children.Add(image);
CurrentImageMode = ExtendedImageMode.AnimatedImage;
loadedImage = null;
#if DEBUG
App.logger.log("Loaded {0} as animated image", loadedLocation);
#endif
imageDisplay = image;
raiseImageUpdated();
}
最终,图像被加载
WebClient client = new WebClient();
ExtendedImage image = new ExtendedImage();
using (Stream source = await client.OpenReadTaskAsync(location))
{
if (location.ToString().EndsWith("gif", StringComparison.InvariantCultureIgnoreCase))
{
image.SetSource(source);
TaskCompletionSource<ExtendedImage> imageLoaded = new TaskCompletionSource<ExtendedImage>();
EventHandler loadingCompleteHandler = new EventHandler((sender, e) =>
{
imageLoaded.SetResult(image);
});
EventHandler<UnhandledExceptionEventArgs> loadingFailedHandler = new EventHandler<UnhandledExceptionEventArgs>((sender, e) =>
{
imageLoaded.SetResult(image);
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Break();
#endif
});
image.LoadingCompleted += loadingCompleteHandler;
image.LoadingFailed += loadingFailedHandler;
image = await imageLoaded.Task;
//Remove handlers, otherwise the object might be kept in the memory
image.LoadingCompleted -= loadingCompleteHandler;
image.LoadingFailed -= loadingFailedHandler;
}
else
{
//... load with native Silverlight methods
}
}
return image;
我们很早就注意到了内存问题,所以控件实现了 IDisposable 接口
public void Dispose()
{
unloadImage();
GC.SuppressFinalize(this);
}
private void unloadImage()
{
SmartDispatcher.BeginInvoke(() =>
{
if (imageDisplay != null)
{
if (imageDisplay is AnimatedImage)
{
if ((imageDisplay as AnimatedImage).Source != null & (imageDisplay as AnimatedImage).Source.Frames != null)
(imageDisplay as AnimatedImage).Source.Frames.Clear();
(imageDisplay as AnimatedImage).Stop();
(imageDisplay as AnimatedImage).Source = null;
}
else if (imageDisplay is Image && ((Image)imageDisplay).Source != GIFplaceholder)
{
(imageDisplay as Image).Source = null;
}
imageDisplay = null;
}
});
}
但是,永远不会对图像调用 Dispose 方法。
我可以做些什么来找出为什么这个对象没有被 GC 拾取?据我所知,我没有注册任何事件处理程序,应该在导航应用程序页面时收集它。我也尝试添加一个析构函数,但是也没有调用这个析构函数。