我有一个项目列表(简单列表框),其中包含主从基础上的图像(如果用户单击列表项,则会打开详细信息页面)。我遇到了非常著名的图像内存泄漏问题,在此处、此处、此处和此处进行了描述。
一种可能的方法是在 NavigatingFrom 时遍历所有图像并清理它们。
在其中一个线程中,我发现了更有趣的解决方案:它会自动清理图像,但这不适用于虚拟化(如果添加私有字段来存储 ImageSource,图像会丢失或混合)。建议的修复是添加依赖属性。
但我仍然面临同样的问题:向下滚动并返回后图像混淆了。看起来依赖属性是随机更改的,但我无法捕捉到它们更改的时刻。
public class SafePicture : ContentControl
{
public static readonly DependencyProperty SafePathProperty =
DependencyProperty.RegisterAttached(
"SafePath",
typeof(string),
typeof(SafePicture),
new PropertyMetadata(OnSourceWithCustomRefererChanged));
public string SafePath
{
get { return (string)GetValue(SafePathProperty); }
set { SetValue(SafePathProperty, value); }
}
private static void OnSourceWithCustomRefererChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null) // New value here
return;
}
public SafePicture()
{
Content = new Image();
Loaded += OnLoaded;
Unloaded += OnUnloaded;
}
private void OnLoaded(object _sender, RoutedEventArgs _routedEventArgs)
{
var image = Content as Image;
if (image == null)
return;
var path = (string)GetValue(SafePathProperty); // Also, tried SafePath (debugger cant catch setter and getter calls), but same result.
image.Source = null;
{
var request = WebRequest.Create(path) as HttpWebRequest;
request.AllowReadStreamBuffering = true;
request.BeginGetResponse(result =>
{
try
{
Stream imageStream = request.EndGetResponse(result).GetResponseStream();
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
if (imageStream == null)
{
image.Source = new BitmapImage { UriSource = new Uri(path, UriKind.Relative) };
return;
}
var bitmapImage = new BitmapImage();
bitmapImage.CreateOptions = BitmapCreateOptions.BackgroundCreation;
bitmapImage.SetSource(imageStream);
image.Source = bitmapImage;
});
}
catch (WebException)
{
}
}, null);
}
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
var image = Content as Image;
if (image == null)
return;
var bitmapImage = image.Source as BitmapImage;
if (bitmapImage != null)
bitmapImage.UriSource = null;
image.Source = null;
}
}
用法:
<wpExtensions:SafePicture SafePath="{Binding ImageUrl}"/>
因此,乍一看,它工作正常,但如果向下滚动并返回,图像会随机更改。
编辑:在这种情况下,现在,我只使用纯 ListBox,没有虚拟化(但在其他情况下期待它)。
EDIT2:重现此问题的示例项目。我相信,它会在一段时间内包含解决方案:https ://simca.codeplex.com/