ImageSourceConverter error for Source=null
Asked Answered
C

3

61

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?

Coffeecolored answered 23/3, 2011 at 0:39 Comment(2)
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).Nisa
Yep, it was definitely causing performance issues. See my answer for details.Nisa
N
104

@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}}"/>
Nisa answered 11/4, 2011 at 22:34 Comment(7)
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.Petrify
Is there a way to specify DependencyProperty.UnsetValue as the TargetNullValue in binding? It may eliminate the need for converter?Polyhydric
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.Piecework
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 errorTerry
i did as you had done but i i getting an error <Window.Resources> <local:NullImageConverter x:Key="nullImageConverter"/> The type 'local:NullImageConverter' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.Kilbride
You are not supposed to throw a NotImplmentedException if you don't support a CovnertBack. Per the MSDN 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.Discriminatory
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.Nenitanenney
K
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.

Kioto answered 27/11, 2018 at 18:51 Comment(0)
N
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");
        }
    }
Narbada answered 10/9, 2013 at 9:30 Comment(2)
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.Coffeecolored
You are binding to a string, yet your property returns object?Lubberly

© 2022 - 2024 — McMap. All rights reserved.