Ron
Ron

Reputation: 13

BitmapImage in UWP display wrong images occasionally

I use BitmapImage when I display avatars in my UWP app. Sometimes the avatars display wrong images (sometimes wrong size and sometimes even displaying images that I have never used in my app).

I have been googling around for a while and found few people having the same problem but none of them is solved. For example, this and this.

The following is the code in my app:

.xaml

<Image>
  <Image.Source>
    <BitmapImage UriSource="{x:Bind Patient.Gender, Mode=OneWay, Converter={StaticResource GenderToAvatarConverter}}" />
  </Image.Source>
</Image>

GenderToAvatarConverter.cs

public sealed class GenderToAvatarConverter : IValueConverter 
{
    object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
    {
        var imagePath = "ms-appx:///Assets/Avatar/Default.png";
        if ((string)value == Gender.MALE.ToString())
        {
            imagePath = "ms-appx:///Assets/Avatar/Man.png";
        }
        else if((string)value == Gender.FEMALE.ToString())
        {
            imagePath = "ms-appx:///Assets/Avatar/Woman.png";
        }

        return new Uri(imagePath);
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Displaying normally

Displaying wrong images

Displaying wrong images again

It would be highly appreciated if someone can solve this problem or how to reproduce it.

Upvotes: 1

Views: 218

Answers (1)

Luke Vanzweden
Luke Vanzweden

Reputation: 646

Heres a way I found to reproduce it.

I have an application where there are users, and a user can have images. When you upload an image, it is saved as 0.png. The BitmapImage loads this, and displays it. Then I delete the image, so the images folder is empty. I then add a new image, which is saved as 0.png. The two images are different, but the paths are the same, and the BitmapImage control continues to display the same image.

From this, I assume that when you create a BitmapImage from a path, it first checks somewhere else to see if the image has already been created, and uses the cache instead. (I also noticed you can only create a BitmapImage on the UI thread).

To work around this, I found you can create a new BitmapImage, and load it from a stream, and the image will not be found in the cache.

Just add a converter:


  public class ImageToBitmapImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string culture)
        {
            BitmapImage bitmapImage = new BitmapImage();

            if (value is Image)
            {
                Image image = (Image)value;

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    memoryStream.Position = 0;
                    bitmapImage.SetSourceAsync(memoryStream.AsRandomAccessStream());
                }

            }

            if (value is string)
            {
                using (FileStream file = new FileStream((string)value, FileMode.Open))
                {
                    IRandomAccessStream fileStream = file.AsRandomAccessStream();
                    bitmapImage.SetSource(fileStream);
                    fileStream.Dispose();
                }
            }

            return bitmapImage;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string culture)
        {
            throw new NotImplementedException();
        }
    }

And use it like:

<Page.Resources>
    <converters:ImageToBitmapImageConverter x:Key="ImageToBitmapImageConverter" />
</Page.Resources>

<Image Source="{Binding CroppedImagePath, Mode=OneWay, Converter={StaticResource ImageToBitmapImageConverter}}"/ >
                                    

Upvotes: 0

Related Questions