title: Image downloader with auto memory cleaning
body: <p>I have a list (simple ListBox) of items with images on master-detail base (if user clicks on list item, details page is opened). I faced quite famous problem with images memory leaks, described <a href="https://stackoverflow.com/questions/13355496/cannot-find-the-memory-leak?lq=1">here</a>, <a href="https://stackoverflow.com/questions/13816569/windows-phone-listbox-with-images-out-of-memory?lq=1">here</a>, <a href="https://stackoverflow.com/questions/7062820/clear-cache-in-window-phone-7">here</a>, and <a href="https://stackoverflow.com/questions/18127027/memory-consumption-of-bitmapimage-image-control-in-windows-phone-8">here</a>. </p>
  
  <p>One possible way is to <a href="https://stackoverflow.com/questions/18886640/run-throguh-visual-tree-and-set-all-images-to-null">run through all images</a> when NavigatingFrom <a href="https://stackoverflow.com/questions/7062820/clear-cache-in-window-phone-7">and clean them</a>.</p>
  
  <p>In <a href="https://stackoverflow.com/questions/17571825/how-to-free-memory-hold-by-images-in-data-template-in-windows-phone-8-app/17573069#comment27921639_17573069">one of the threads</a>, i found more interesting solution: it cleans images automatically, but that is not working for virtualization (images are lost or mixed, if to add private field for storing ImageSource). Suggested fix was to add dependency property. </p>
  
  <p>But i'm still facing the same problem: images are mixed up after scrolling down and returning up. Looking like dependency property are changed randomly, but i cant catch the moment when they are changing.</p>
  
  <pre><code>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 =&gt;
              {
                  try
                  {
                      Stream imageStream = request.EndGetResponse(result).GetResponseStream();
                      DispatcherHelper.CheckBeginInvokeOnUI(() =&gt;
                      {
                          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;
      }
  }
  </code></pre>
  
  <p>Usage:</p>
  
  <pre><code>&lt;wpExtensions:SafePicture SafePath="{Binding ImageUrl}"/&gt;
  </code></pre>
  
  <p>So, at first glance, it works fine, but if to scroll down and return up, images are changed randomly.</p>
  
  <p>EDIT: in this case, for now, i'm using only pure ListBox, without virtualization (but expecting it in other cases).</p>
  
  <p>EDIT2: sample project to reproduce this problem. I believe, it would contain solution in a while: <a href="https://simca.codeplex.com/" rel="nofollow noreferrer">https://simca.codeplex.com/</a></p>