3

I am trying to load a BitmapImage at runtime from a URI. I use a default image in my XAML user control which I'd like to replace via databindings. This works.

The problem I'm having is in situations where an invalid file is used for the replacement image (maybe it's a bad URI, or maybe the URI specifies a non-image file). When this happens, I want to be able to check the BitmapImage object to see if it was correctly loaded. If not, I want to stick to the default image being used.

Here's the XAML:

<UserControl x:Class="MyUserControl">
    <Grid>
        <Image
            x:Name="myIcon"
            Source="Images/default.png" />
    </Grid>
</UserControl>

And the relevant codebehind:

public static readonly DependencyProperty IconPathProperty =
    DependencyProperty.Register(
        "IconPath",
        typeof(string),
        typeof(MyUserControl),
        new PropertyMetadata(null, new PropertyChangedCallback(OnIconPathChanged)));

public string IconPath
{
    get { return (string)GetValue(IconPathProperty); }
    set { SetValue(IconPathProperty, value); }
}

private static void OnIconPathChanged(
    object sender,
    DependencyPropertyChangedEventArgs e)
{
    if (sender != null)
    {
        // Pass call through to the user control.
        MyUserControl control = sender as MyUserControl;
        if (control != null)
        {
            control.UpdateIcon();
        }
    }
}

public void UpdateIcon()
{
    BitmapImage replacementImage = new BitmapImage();

    replacementImage.BeginInit();
    replacementImage.CacheOption = BitmapCacheOption.OnLoad;

    // Setting the URI does not throw an exception if the URI is
    // invalid or if the file at the target URI is not an image.
    // The BitmapImage class does not seem to provide a mechanism
    // for determining if it contains valid data.
    replacementImage.UriSource = new Uri(IconPath, UriKind.RelativeOrAbsolute);

    replacementImage.EndInit();

    // I tried this null check, but it doesn't really work.  The replacementImage
    // object can have a non-null UriSource and still contain no actual image.
    if (replacementImage.UriSource != null)
    {
        myIcon.Source = replacementImage;
    }
}

And here's how I might create an instance of this user control in another XAML file:

<!--
  My problem:  What if example.png exists but is not a valid image file (or fails to load)?
-->
<MyUserControl IconPath="C:\\example.png" />

Or maybe someone can suggest a different/better way to go about loading an image at runtime. Thanks.

RobotNerd
  • 2,608
  • 3
  • 29
  • 28

4 Answers4

1

Well, BitmapImage class has two events, which will be raised when either download or decoding has failed.

yourBitmapImage.DownloadFailed += delegate { /* fall to your def image */ }
yourBitmapImage.DecodeFailed += delegate { /* fall to your def img */ }

On a side note, if you're trying to implement fallback placeholder: http://www.markermetro.com/2011/06/technical/mvvm-placeholder-images-for-failed-image-load-on-windows-phone-7-with-caliburn-micro/ seems nice.

Erti-Chris Eelmaa
  • 25,338
  • 6
  • 61
  • 78
1

It's crude, but I found that a non-valid BitmapImage will have width and height of 0.

    BitmapImage image;
    if(image.Width > 0 && image.Height > 0) 
    {  
        //valid image 
    }     
James R
  • 156
  • 1
  • 11
  • Yes it is a hack, but until I found better solution I would use this. And do not know why BitmapImage.cs does not have CheckCache as public method, or CreationCompletedDone event or something similar downloadsuccess and downloadfailed are not enough in many cases. And while I am writing this I should check Width > 1 and Height > 1, instead of 0. Thanks for solution. – I.Step Apr 16 '20 at 21:40
0

You can try this check

        if (bitmapImage.UriSource==null || bitmapImage.UriSource.ToString()).Equals(""))
        {
            Console.WriteLine("path null");
        }
        else
        {
            bitmapImage.EndInit();
        }
Ana
  • 841
  • 10
  • 28
-2

This has already been answered. Please have a look at this and this. I think that both of them somewhat answer your question but I would prefer the former approach as it even checks for the contentType of the remote resource.

You can also have a look at this post.

Update:

In case of local files, this can be checked by simply creating an Image object using the Uri, or the path. If it is successful, it means the image is a valid image:

try
{
    Image image = Image.FromFile(uri);
    image.Dispose();
}
catch (Exception ex)
{
    //Incorrect uri or filetype.
}
Community
  • 1
  • 1
Shakti Prakash Singh
  • 2,414
  • 5
  • 35
  • 59
  • 2
    I don't think these solutions apply to my situation because I'm using URIs point to local files (nothing is going over HTTP). I actually tried the solution in your first link, and it threw an exception stating that the URI prefix was not recognized. The type of URI string I'm using is of the form: "pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml" – RobotNerd Apr 20 '12 at 16:46