views:

28

answers:

1

I've created a small user control consisting of a button whose content is an Image. I created an "ImageSource" dependency property on the user control in order to bind to it from the Image inside the button.

However in the XAML where I placed an instance of my user control setting the property throws an error at runtime :

<ctrl:ImageButton ImageSource="/Resources/Images/Icons/x.png" Command="{Binding Reset}"  DisabledOpacity="0.1"/>

and at runtime :

'/Resources/Images/Icons/x.png' string is not a valid value for 'ImageSource' property of type 'ImageSource'. 'ImageSource' type does not have a public TypeConverter class.

I then created a converter :

public class StringToBitmapImage : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return new BitmapImage(new Uri((string) value, UriKind.RelativeOrAbsolute));
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

and then decorated my dependency property with it :

    [TypeConverter(typeof(StringToBitmapImage))]
    public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
        LambdaHelper.GetMemberName<ImageButton>(ib => ib.ImageSource), typeof (ImageSource), typeof (ImageButton));
    [TypeConverter(typeof(StringToBitmapImage))]
    public ImageButton ImageSource
    {
        get { return (ImageButton)GetValue(ImageSourceProperty); }
        set { SetValue(ImageSourceProperty, value); }
    }

but still WPF does not convert my string to an ImageSource (BitmapImage) instance...

What to do?

+1  A: 

There are several incorrect things here:

First, your CLR property is returning an ImageButton whereas the dependency property is defined as an ImageSource.

Second, a type converter is not the same as a binding value converter. Your type converter should derive from TypeConverter and be applied on the ImageSource class rather than on the property itself.

Third, the framework ImageSource type already has a TypeConverterAttribute with ImageSourceConverter as the type converter so everything should work out of the box without having to write a custom converter. Make sure you're not referencing another custom ImageSource class in another namespace.

To finish, use ImageBrush.ImageSource.AddOwner rather than redefining a whole new dependency property.

Edit: to answer Berryl's comment:

public static readonly DependencyProperty ImageSourceProperty = ImageBrush.ImageSource.AddOwner(typeof(ImageButton);

This piece of code will reuse the existing ImageSource property rather than defining a new (remember that each different dependency property gets registered in a global static dictionary), only defining a new owner and optionally a new metadata. It's like OverrideMetadata but from an outside class.

Julien Lebosquain
@Julien: can you show in code how that last part (ImageBrush.ImageSource.AddOwner) would be used? Cheers
Berryl
Thank you! It worked! :)
Andrei Rinea