问题
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;
}
}
}
回答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");
}
....
回答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>
回答3:
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
来源:https://stackoverflow.com/questions/4997365/solution-to-binding-errors-thrown-by-setting-image-source-to-a-binding-to-null