Question

I've got the following Converter in my WPF application:

[ValueConversion(typeof(byte[]), typeof(ImageSource))]
public class ReturnLabelImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var byteArray = value as byte[];
        if (byteArray == null)
            return new BitmapImage();
        return BuildReturnLabelImageSource(byteArray);
    }

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

    public static ImageSource BuildReturnLabelImageSource(byte[] image)
    {
        if (image == null)
            return null;
        var imgBrush = new BitmapImage
        {
            CacheOption = BitmapCacheOption.OnLoad,
            CreateOptions = BitmapCreateOptions.PreservePixelFormat
        };
        imgBrush.BeginInit();
        imgBrush.StreamSource = ConvertImageToMemoryStream(image);
        imgBrush.EndInit();
        return imgBrush;
    }

    public static MemoryStream ConvertImageToMemoryStream(byte[] img)
    {
        var ms = new MemoryStream(img);
        return ms;
    }
}

My code reviewer gave me the suggestion that the stream should be disposed of. It's not readily apparent to me how I should do that; the best idea I came up with was this:

    public static ImageSource BuildReturnLabelImageSource(byte[] image)
    {
        if (image == null)
            return null;
        var imgBrush = new BitmapImage
        {
            CacheOption = BitmapCacheOption.OnLoad,
            CreateOptions = BitmapCreateOptions.PreservePixelFormat
        };
        using (var stream = ConvertImageToMemoryStream(image))
        {
            imgBrush.BeginInit();
            imgBrush.StreamSource = stream;
            imgBrush.EndInit();
            return imgBrush;
        }
    }

Am I on the right track here, or should I be doing this differently?

Was it helpful?

Solution

The documentation of BitmapImage.StreamSource says:

Set the CacheOption property to BitmapCacheOption.OnLoad if you wish to close the stream after the BitmapImage is created. The default OnDemand cache option retains access to the stream until the bitmap is needed, and cleanup is handled by the garbage collector.

Since you set CacheOption accordingly, imgBrush should no longer require access to the stream after EndInit (at least, that's how I would interpret the quoted paragraph), so your code looks correct to me.


PS: Yes, it's good practice to dispose all IDisposables, but, in your case, it's just a memory stream. In contrast to a file stream or a database connection, a memory stream does not have any unmanaged resources that need to be released. In fact, according to the reference source, all that MemoryStream.Dispose does is to ensure that an exception is thrown if you try to read it again, so I wouldn't lose any sleep over it.

OTHER TIPS

Internally, the

EndInit() 

function will call

FinalizeCreation()

which load the data from the stream (if set). Then you can dispose your Memory stream without fears. It is usually a good practice to dispose explicitely such ref.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top