This project has moved. For the latest updates, please go here.

MapImage Source: This Freezable cannot be frozen

Nov 6, 2013 at 8:30 PM
Edited Nov 6, 2013 at 9:14 PM
The MapImage example in the WPF sample application works well with the jpg bundled in the project. However if I change the source to an external URL I get the error: This Freezable cannot be frozen.

Steps to reproduce:
In MainWindow.xaml change
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750" Source="10_535_330.jpg" Opacity="0.5"/>
to
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750" Source="http://www.helpinghomelesscats.com/images/cat1.jpg" Opacity="0.5"/>
Thanks,
Rob

Update:
I spent a bit of time experimenting with MapImage.SourceChanged. It seems to be fired multiple times when the ImageSource is an external url. In WPF there is a BitmapSource.IsDownloading property which is set to false on the final time SourceChanged fires. IsDownloading does not exist in Silverlight, and I haven't tried it in WinRT (on a Win 7 box at work).

Here's the workaround I came up with:
private void SourceChanged(ImageSource image)
        {
#if !SILVERLIGHT && !NETFX_CORE
            if (!(image as BitmapSource).IsDownloading)
            {
#endif
                var imageBrush = new ImageBrush
                {
                    ImageSource = image,
                    RelativeTransform = imageTransform
                };

                imageBrush.Freeze();
                Fill = imageBrush;
#if !SILVERLIGHT && !NETFX_CORE
            }
#endif
        }
Coordinator
Nov 6, 2013 at 10:14 PM
Edited Nov 6, 2013 at 10:14 PM
Thanks for pointing this out. However, your workaround has a problem. If image is not a BitmapImage, you will be calling IsDownloading on a null reference.

Anyway, I will add something like this to MapImage with the next release:
        private void SourceChanged(ImageSource image)
        {
            var imageBrush = new ImageBrush
            {
                ImageSource = image,
                RelativeTransform = imageTransform
            };

#if !SILVERLIGHT && !NETFX_CORE
            if (imageBrush.CanFreeze)
            {
                imageBrush.Freeze();
            }
#endif
            Fill = imageBrush;
        }
Nov 7, 2013 at 12:33 PM
Edited Nov 7, 2013 at 12:52 PM
Excellent, thanks.

I agree that my workaround is specific to BitmapSource, and I do prefer the more generic solution.

For some reason SourceChanged is firing multiple times in the example project, but not in my own. I'm still trying to track down the difference. To get it working in my own project, I ended up subscribing to the BitmapSource.DownloadCompleted event. Unfortunately, when I try to unsubscribe the BitmapSource is frozen. This isn't as clean as I'd like but it works for now.
    private void SourceChanged(ImageSource image)
    {
        BitmapSource source = image as BitmapSource;
        if (source != null && source.IsDownloading)
        {
            source.DownloadCompleted += source_DownloadCompleted;
        }
        else
        {
            PaintImage(image);
        }
    }

    private void source_DownloadCompleted(object sender, EventArgs e)
    {
        PaintImage(sender as BitmapSource);
    }

    private void PaintImage(ImageSource image)
    {
        var imageBrush = new ImageBrush
        {
            ImageSource = image,
            RelativeTransform = imageTransform
        };

        if (image.CanFreeze)
        {
            imageBrush.Freeze();
        }

        Fill = imageBrush;
    }
Nov 8, 2013 at 7:17 PM
Edited Nov 8, 2013 at 7:18 PM
I suggest a minor change to handle the Source being set to null. Maybe something like this:
    private void SourceChanged(ImageSource image)
    {
        if (image != null)
        {
            var imageBrush = new ImageBrush
            {
                ImageSource = image,
                RelativeTransform = imageTransform
            };

#if !SILVERLIGHT && !NETFX_CORE
            if (imageBrush.CanFreeze)
            {
                imageBrush.Freeze();
            }
#endif
            Fill = imageBrush;
        }
    }