Image Downloader com limpeza automática de memória

Eu tenho uma lista (ListBox simples) de itens com imagens na base de detalhes mestres (se o usuário clicar no item da lista, a página de detalhes é aberta). Eu enfrentei um problema bastante famoso com vazamentos de memória de imagens, descritosAqui, Aqui, AquieAqui.

Uma maneira possível épercorrer todas as imagens quando navegando a partir dee limpe-os.

Emum dos fios, encontrei uma solução mais interessante: limpa imagens automaticamente, mas isso não está funcionando para virtualização (imagens são perdidas ou misturadas, se for adicionar campo privado para armazenar ImageSource). A correção sugerida foi adicionar propriedade de dependência.

Mas ainda estou enfrentando o mesmo problema: as imagens são misturadas depois de rolar para baixo e retornar. Olhando como propriedade de dependência são alterados aleatoriamente, mas eu não consigo pegar o momento em que eles estão mudando.

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;
    }
}

Uso:

<wpExtensions:SafePicture SafePath="{Binding ImageUrl}"/>

Então, à primeira vista, funciona bem, mas se rolar para baixo e retornar, as imagens são alteradas aleatoriamente.

EDIT: neste caso, por enquanto, eu estou usando apenas ListBox puro, sem virtualização (mas esperando isso em outros casos).

EDIT2: projeto de exemplo para reproduzir esse problema. Eu acredito, ele conteria solução em um tempo:https://simca.codeplex.com/

questionAnswers(1)

yourAnswerToTheQuestion