Descargador de imágenes con limpieza automática de memoria.

Tengo una lista (simple ListBox) de elementos con imágenes en la base de detalles maestros (si el usuario hace clic en el elemento de la lista, se abre la página de detalles). Me enfrenté a un problema bastante famoso con las imágenes con pérdidas de memoria, descritoaquí, aquí, aquíyaquí.

Una forma posible escorrer a través de todas las imágenes cuando navega desdey limpiarlos.

Enuno de los hilos, encontré una solución más interesante: limpia las imágenes automáticamente, pero eso no funciona para la virtualización (las imágenes se pierden o se mezclan, si se agrega un campo privado para almacenar ImageSource). La solución sugerida era agregar propiedad de dependencia.

Pero todavía estoy enfrentando el mismo problema: las imágenes se mezclan después de desplazarse hacia abajo y volver a subir. Al parecer, las propiedades de dependencia se cambian aleatoriamente, pero no puedo detectar el momento en que están cambiando.

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}"/>

Entonces, a primera vista, funciona bien, pero si para desplazarse hacia abajo y regresar, las imágenes se cambian aleatoriamente.

EDITAR: en este caso, por ahora, solo uso ListBox puro, sin virtualización (pero esperándolo en otros casos).

EDIT2: proyecto de muestra para reproducir este problema. Creo que contendría solución en un momento:https://simca.codeplex.com/

Respuestas a la pregunta(1)

Su respuesta a la pregunta