0

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;
        }
    }
}
Yael
  • 1,566
  • 3
  • 18
  • 25
Firoso
  • 6,647
  • 10
  • 45
  • 91

3 Answers3

2

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>
ponolson
  • 46
  • 5
1

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");
      }
      ....
HCL
  • 36,053
  • 27
  • 163
  • 213
  • the source is Stream.Null or null, i've attempted both. – Firoso Feb 14 '11 at 21:24
  • There is no empty image source pre-defined... but now I'm getting crious *laughs* – Firoso Feb 14 '11 at 21:51
  • Sorry, I'm not native english speaking. I don't understand your statement. – HCL Feb 14 '11 at 21:53
  • I'm not sure how to implement what you are proposing, it is not making sense to me HCL. – Firoso Feb 14 '11 at 21:55
  • Copy paste the code, look into the msdn-article I have given you on how to use the value converter. If the copy-paste solution does not work, make an empty ImageSource, e.g. a BitmapSource that points to an empty png and return in case of null this ImageSource (Line 4). However I doubt that this will be necessary. The error is pretty clear described in the exception you have posted. – HCL Feb 14 '11 at 22:14
0

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

Community
  • 1
  • 1
TripleAntigen
  • 2,221
  • 1
  • 31
  • 44