0

I've got a ListView containing a GridView with an ObservableCollection as its ItemsSource. One column displays an image from a bound property containing the path. There are multiple entries with the same image path. Now I'm trying to replace one image file and reload the displayed image for all associated entries.

Here's what my cell template looks like so far (the CacheOption is needed so the image file isn't in use when replacing it):

<GridViewColumn.CellTemplate>
  <DataTemplate>
    <Image RenderOptions.BitmapScalingMode="HighQuality">
      <Image.Source>
        <BitmapImage UriSource="{Binding Image}" CacheOption="OnLoad" />
      </Image.Source>
    </Image>
  </DataTemplate>
</GridViewColumn.CellTemplate>

The usual way to reload an image seems be to create a new BitmapImage with BitmapCreateOptions.IgnoreImageCache and assign it to the corresponding Image.Source, replacing the old BitmapImage.

Obviously, it isn't very practical do to this manually for hundreds of ListView entries. I guess I could refresh the ItemsSource property if I use CreateOptions="IgnoreImageCache" for the BitmapImage inside my cell template, but I'm unsure about the side effects (e. g. bypassing the cache when using the same image multiple times).

What would be the proper way to reload these images?

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
Eric
  • 25
  • 1
  • 4
  • For me, in a WinRT application nothing else worked as expected so I ended up with a converter that does this logic. – kirotab Oct 29 '15 at 07:29
  • @kirotab That's another possible solution to consider, thanks. Could you give me a short description of what your converter did? Take a path and return a BitmapImage? I guess it would then suffice to raise a PropertyChanged event for the path to trigger the reload. – Eric Oct 30 '15 at 04:45

1 Answers1

0

I've posted this in another question but no idea if it's better to link it, also somebody else might turn out with better idea. I'm binding with image path by the way.


Here's what I ended up with in my project (and I've got to say it took quite a while testing different things that seemed to almost work). You can see the commented code which was also not working 100% don't remember why)

So all my Images from app assets that are starting with "ms-appx:" I use with setting the source without loading to stream, because these never change (default images etc)

The other images that are created or changed by the user I had to reload and set the source with the result of the file read (otherwise when they were changed sometimes they were not updating)

So basically I use this converter on almost all of the places that I use images that can change (without changing their name).

define your converter:

<converters:ImageConverter x:Key="ImageConverter" /> 

And then use like this

<Image Source="{Binding PictureFilename, Converter={StaticResource ImageConverter}}"
       HorizontalAlignment="Center"
       VerticalAlignment="Center"/>

(Another workaround is to name your images differently and then when you update the source path it works fine.)

public class ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        try
        {
            var CapturedImage = new BitmapImage();
            CapturedImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
            if (((string)value).StartsWith("ms-appx:"))
            {
                CapturedImage.UriSource = new Uri((string)value, UriKind.RelativeOrAbsolute);
                return CapturedImage;

            }
            var file = (StorageFile.GetFileFromPathAsync(new Uri((string)value, UriKind.RelativeOrAbsolute).LocalPath).AsTask().Result);
            using (IRandomAccessStream fileStream = file.OpenAsync(FileAccessMode.Read).AsTask().Result)
            {
                CapturedImage.SetSource(fileStream);
                return CapturedImage;

            }
        }
        catch (Exception e)
        {
            Logger.Error("Exception in the image converter!", e);
            return new BitmapImage();
        }

        //BitmapImage img = null;
        //if (value is string)
        //{
        //    img = new BitmapImage();
        //    img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
        //    img.UriSource = new Uri((string)value, UriKind.RelativeOrAbsolute);
        //}

        //if (value is Uri)
        //{
        //    img = new BitmapImage();
        //    img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
        //    img = new BitmapImage((Uri)value);
        //}

        //return img;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
kirotab
  • 1,296
  • 1
  • 11
  • 18
  • Thanks. Using a converter to convert a path to a BitmapImage and binding that to Image.Source works. In my case however, I didn't have to read the file manually. It worked as described [here](http://stackoverflow.com/a/1491655/1423577). – Eric Oct 30 '15 at 07:55
  • I had to do that because when my files were changed it was still not updating in some cases, that is if the server synchronization overwrite the image with the same name (maybe some caching was still left in the memory) – kirotab Oct 30 '15 at 08:07