0
votes

I've got a scenario where I have Image Sources set to null which are resolved later and then displayed. Any good way to prevent my code from throwing binding errors?

An example:

System.Windows.Data Error: 23 : Cannot convert '' from type '' to type 'System.Windows.Media.ImageSource' for 'en-US' 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)'

XAML

<Image x:Name="image" Height="Auto" Width="Auto" Opacity="0">
    <Image.Effect>
        <DropShadowEffect/>
    </Image.Effect>
    <Image.Source>
        <Binding Path="ImageStream">
            <Binding.ValidationRules>
                <validationRules:NotNullStreamValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </Image.Source>
</Image>

C#

namespace FlickrDemo.ViewModel
{
    public class FlickrPhotoViewModel : ViewModelBase
    {
        public const string ImageStreamPropertyName = "ImageStream";

        private Stream _imageStream = null;

        public Stream ImageStream
        {
            get
            {
                return _imageStream;
            }

            set
            {
                if (_imageStream == value)
                {
                    return;
                }
                _imageStream = value;

                RaisePropertyChanged(ImageStreamPropertyName);
            }
        }

        public const string IsLoadingPropertyName = "IsLoading";

        private bool _isLoading = false;

        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }

            set
            {
                if (_isLoading == value)
                {
                    return;
                }

                _isLoading = value;

                RaisePropertyChanged(IsLoadingPropertyName);
            }
        }

        public const string PhotoIDPropertyName = "PhotoID";

        private string _photoID = String.Empty;

        public string PhotoID
        {
            get
            {
                return _photoID;
            }

            set
            {
                if (_photoID == value)
                {
                    return;
                }

                var oldValue = _photoID;
                _photoID = value;

                RaisePropertyChanged(PhotoIDPropertyName);
            }
        }

        public FlickrPhotoViewModel(string photoID)
        {
            this.PropertyChanged += async (s, e) =>
            {
                if (e.PropertyName == ImageStreamPropertyName)
                {
                    if (!(ImageStream == null || ImageStream == Stream.Null))
                    {
                        IsLoading = false;
                    }
                }
            };
            IsLoading = true;
            PhotoID = photoID;
        }
    }
}
3
Can you post your code - both XAML and view modelChrisF♦
Too much code ;) I was just thinking of the property you bind to.ChrisF♦
@ChrisF Any Ideas? I'm at a loss.Firoso
Sorry - While I've done WPF, I'm mainly Silverlight at the moment. I'd be reluctant to suggest anything as it could well be misleading.ChrisF♦

3 Answers

1
votes

The problem is the datatype of your ImageStream property. There is no converter that knows how to handle the null-situation:

System.Windows.Data Error: 23 : Cannot convert '' from type '' to type 'System.Windows.Media.ImageSource' for 'en-US' culture with default conversions; consider using Converter property of Binding

One possibility to solve this problem is to make your own IValueConverter implementation. If the input value is a stream, return it. If not, return null. If this does not work, return an empty dummy ImageSource.

Something like:

public class ImageStreamForwardConverter : IValueConverter{
    public object Convert(object value, Type targetType, object parameter, CultureInfo    culture){
      if(null == value){
         return null;
      }else if(value is Stream){
         return value;
      }else{
         throw new InvalidOperationException("Unsupported type");
      }
      ....
2
votes

I ran into the same problem trying to use a string URI (rather than a Stream). I resolved the issue by setting up a property on my view model of type ImageSource, which is the type of the Source property on Image, and binding Source to that property. This gets any automatic conversion out of the mix. Within the new property, handle the null case, then defer to the standard ImageSourceConverter. In your case, I think this would look something like this:

Code:

public const string ImageStreamPropertyName = "ImageStream";

private Stream _imageStream = null;

public Stream ImageStream
{
    get
    {
        return _imageStream;
    }

    set
    {
        if (_imageStream == value)
        {
            return;
        }
        _imageStream = value;

        RaisePropertyChanged(ImageStreamPropertyName);
        // Raise for ImageSource too since it changes with ImageStream
        RaisePropertyChanged("ImageSource");
    }
}

public ImageSource ImageSource
{
    get
    {
        if (ImageStream == null)
            return null;

        return (ImageSource)new ImageSourceConverter().ConvertFrom(ImageStream);
    }
}

XAML:

    <Image.Source>
        <Binding Path="ImageSource" />
    </Image.Source>
0
votes

Pat's answer at the below link worked great for me, it involves a simple value converter that instead returns DependencyProperty.UnsetValue in the case of a null.

ImageSourceConverter error for Source=null