60

I'm binding the Source property of an Image to a string. This string may be null in which case I just don't want to display an Image. However, I'm getting the following in my Debug output:

System.Windows.Data Error: 23 : Cannot convert '<null>' from type '<null>' to type 'System.Windows.Media.ImageSource' for 'en-AU' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: ImageSourceConverter cannot convert from (null). at System.ComponentModel.TypeConverter.GetConvertFromException(Object value) at System.Windows.Media.ImageSourceConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value) at MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)'

I'd prefer if this wasn't displayed as it's just noise - is there any way to suppress it?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Kai G
  • 3,371
  • 3
  • 26
  • 30
  • 5
    I'm not so sure that it's just noise. In my app, I believe it's causing some performance issues (when loading all of the null images). – Pat Apr 11 '11 at 22:25
  • 1
    Yep, it was definitely causing performance issues. See my answer for details. – Pat Apr 11 '11 at 22:29

3 Answers3

103

@AresAvatar is right in suggesting you use a ValueConverter, but that implementation does not help the situation. This does:

public class NullImageConverter :IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return DependencyProperty.UnsetValue;
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // According to https://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback(v=vs.110).aspx#Anchor_1
        // (kudos Scott Chamberlain), if you do not support a conversion 
        // back you should return a Binding.DoNothing or a 
        // DependencyProperty.UnsetValue
        return Binding.DoNothing;
        // Original code:
        // throw new NotImplementedException();
    }
}

Returning DependencyProperty.UnsetValue also addresses the performance issues from throwing (and ignoring) all those exceptions. Returning a new BitmapSource(uri) would also get rid of the exceptions, but there is still a performance hit (and it isn't necessary).

Of course, you'll also need the plumbing:

In resources:

<local:NullImageConverter x:Key="nullImageConverter"/>

Your image:

<Image Source="{Binding Path=ImagePath, Converter={StaticResource nullImageConverter}}"/>
Pat
  • 16,515
  • 15
  • 95
  • 114
  • 4
    Amazing how much faster my code runs now when I consider a null value for an image source. Thanks for that, though I would recommend also handling the string.IsNullOrWhitespace case as well if 'value' is a string. – Andrew Garrison Feb 07 '12 at 20:28
  • 3
    Is there a way to specify DependencyProperty.UnsetValue as the TargetNullValue in binding? It may eliminate the need for converter? – Nitesh Jul 23 '12 at 06:48
  • 1
    I tested this with great success: `TargetNullValue={x:Static DependencyProperty.UnsetValue}` **note:** If it's an empty string, it will not work. One possible solution if you are doing something like building a string path in a getter, is to simply return `null` instead of `string.Empty`. – erodewald Apr 02 '13 at 17:50
  • This can be made even simpler by just returning the value in the Convert function. In effect this will simple pipe through the value unaltered but it will not show the binding error – buckley Jun 11 '13 at 09:02
  • i did as you had done but i i getting an error ` ` The type 'local:NullImageConverter' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built. – omini data May 11 '16 at 18:46
  • You are not supposed to throw a `NotImplmentedException` if you don't support a CovnertBack. [Per the MSDN](https://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback(v=vs.110).aspx#Anchor_1) you should either return `DependencyProperty.UnsetValue` or `Binding.DoNothing` depending on if you want the binding to use the fallback value and default value or not. – Scott Chamberlain May 13 '16 at 15:42
  • omini data - you need to make sure you put the converter at the right namespace. local: will only work if that is where you put it. – Epirocks Aug 18 '17 at 17:43
19

I used Pat's ValueConverter technique and it worked great. I also tried the TargetNullValue technique, by flobodob from here, and it also works great. It's easier and cleaner.

<Image Source="{Binding LogoPath, TargetNullValue={x:Null}}" />

TargetNullValue is simpler, and requires no converter.

Miyamoto Musashi
  • 502
  • 7
  • 15
6

Bind your image directly on an object and return "UnsetValue" if necessary

<Image x:Name="Logo" Source="{Binding ImagePath}"  />

The property in your ViewModel :

    private string _imagePath = string.Empty;
    public object ImagePath 
    {
        get
        {
            if (string.IsNullOrEmpty(_imagePath))
                return DependencyProperty.UnsetValue;

            return _imagePath;
        }
        set
        {
            if (!(value is string)) 
                return;

            _imagePath = value.ToString();
            OnPropertyChanged("ImagePath");
        }
    }
scrat789
  • 2,961
  • 3
  • 30
  • 26
  • 1
    While that probably works I think Pat's answer is better because you only have to define the converter once - with your solution you'd have to re-implement this for every Image property. – Kai G Sep 11 '13 at 17:02
  • You are binding to a string, yet your property returns object? – pixel Mar 08 '17 at 21:29