views:

775

answers:

1

I am binding an Image's Source property to a URI string property on the model:

<Image Validation.ErrorTemplate="{StaticResource validationTemplate}">
  <Image.Source>
    <Binding Path="LargeImage.ImageUri">
      <Binding.ValidationRules>
        <ExceptionValidationRule/>
      </Binding.ValidationRules>
    </Binding>
  </Image.Source>
</Image>

<ControlTemplate x:Key="validationTemplate">
  <Border BorderThickness="2" CornerRadius="2" BorderBrush="Red">
    <AdornedElementPlaceholder/>
  </Border>
</ControlTemplate>

I want the Image to display a red border when LargeImage.ImageUri isn't a valid image, but this isn't happening.

Is this because the problem is with converting the bound value, rather than with setting it?

I can see that an exception is thrown converting the string ImageUri to an ImageSource:

System.Windows.Data Error: 18 : Cannot convert 'C:\not-an-image.txt' from type 'String' to type 'System.Windows.Media.ImageSource' for 'en-US' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: No imaging component suitable to complete this operation was found. ---> System.Runtime.InteropServices.COMException (0x88982F50): Exception from HRESULT: 0x88982F50
   --- End of inner exception stack trace ---
   at MS.Internal.HRESULT.Check(Int32 hr)
   at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream, SafeFileHandle& safeFilehandle)
   at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
   at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy)
   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)'
System.Windows.Data Error: 6 : 'TargetDefaultValueConverter' converter failed to convert value 'C:\not-an-image.txt' (type 'String'); fallback value will be used, if available. BindingExpression:Path=LargeImage.ImageUri; DataItem='ItemSettings' (HashCode=60569775); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource') NotSupportedException:'System.NotSupportedException: No imaging component suitable to complete this operation was found. ---> System.Runtime.InteropServices.COMException (0x88982F50): Exception from HRESULT: 0x88982F50
   --- End of inner exception stack trace ---
   at MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)
   at MS.Internal.Data.TargetDefaultValueConverter.Convert(Object o, Type type, Object parameter, CultureInfo culture)
   at System.Windows.Data.BindingExpression.ConvertHelper(IValueConverter converter, Object value, Type targetType, Object parameter, CultureInfo culture)'
+1  A: 

Is this because the problem is with converting the bound value, rather than with setting it?

In a way yes, if you mean setting/updating the binding source rather than the binding target, see the MSDN description of ExceptionValidationRule:

Represents a rule that checks for exceptions that are thrown during the update of the binding source property.

The highlighted phrase is key here: the rule applies to binding operations updating the source, not the target. In your case Image.Source is the binding target while LargeImage.ImageUri is the binding source, hence the other way round concerning what you are trying to achieve.

Essentially you would like to validate the existing model rather than user input (with the canonical example being a TextBox accepting user input and applying some constraints, e.g. string length or integer range). However, by means of the ValidationRule Class WPF data binding is only targeting the latter scenario:

Provides a way to create a custom rule in order to check the validity of user input.

See section Data Validation within Data Binding Overview for more details on this.

Steffen Opel