简体   繁体   中英

WPF: Memory implications of using ValueConverter to create BitmapImage for ImageSource

I had an issue with using Images and provide a right-click context menu for deleting the Image.

Originally I was binding the absolute file path:

<Image Source="{Binding Path=ImageFileName} .../>

where ImageFileName is something like C:\\myapp\\images\\001.png .

I was getting an error, The process cannot access the file 'X' because it is being used by another process . After a lot of research, I figured out the necessary code change.

I used this Stackoverflow answer: Delete a file being used by another process and put the code into a ValueConverter .

XAML:

<Image Source="{Binding Path=ImageFileName, 
    Converter={StaticResource pathToImageConverter}}" ...>

Value Converter:

public class PathToImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        try
        {
            String fileName = value as String;
            if (fileName != null)
            {
                BitmapImage image = new BitmapImage();
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.UriSource = new Uri(fileName);
                image.EndInit();
                return image;
            }
            return new BitmapImage();
        }
        catch
        {
            return new BitmapImage();
        }
    }

    public object ConvertBack(object value, Type targetType,
                              object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  1. The concern I have is memory usage. When I add Images to my Container, I see memory increase. However, when I delete Images, and the underlying file is deleted, I do not see any memory being freed up.

  2. I've also always thought of Bitmaps as a very inefficient file format, since they are uncompressed, and tend to be HUGE compared to a JPEG or PNG file. Is the System.Windows.Media.Imaging.BitmapSource class actually creating an uncompressed image out of my PNG?

Thanks very much in advance!

Philip

WPF caches up to 300 ImageSource objects (using weak references) when you load an image from a URI. To avoid this, set the BitmapCreateOptions.IgnoreImageCache option or use a FileStream to load the image instead.

Note that this could have an adverse effect on your app's performance, especially in a situation where you're scrolling and loading images in a virtualized ListBox . But if you're loading really large images, you might want to avoid it.

Use the following code in your converter (note also the added image.Freeze call, which improves performance by making the object read-only and thread-agnostic):

using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
    BitmapImage image = new BitmapImage();
    image.BeginInit();
    image.CacheOption = BitmapCacheOption.OnLoad;
    image.StreamSource = fs;
    image.EndInit();
    image.Freeze();
    return image;
}

Another possible performance optimization is to set DecodePixelWidth to downscale the image.

Regarding your concern about formats -- bitmap is a general name for pixel-based images (in contrast to vector-based images). The file formats you mentioned (PNG, JPEG) are bitmaps as well, they're just encoded (possibly with some compression). The BitmapImage class uses WIC to decode them so they can be rendered on the screen.

Try this..

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Convert(new[] { value }, targetType, parameter, culture);
        }

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

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                string imageUri = String.Format((parameter ?? "{0}").ToString(), values);
                return new BitmapImage(new Uri(imageUri, UriKind.RelativeOrAbsolute));
            }
            catch
            {
                return null;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM