views:

161

answers:

2

To describe my problem i have created a small application. At first the Usercontrol:

<UserControl x:Class="WpfApplication10.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="This" DataContext="{Binding ElementName=This}"
    >    
    <Image Source="{Binding Path=MyImageSource}" ></Image>
</UserControl>

second the TestApp:

<Window x:Class="WpfApplication10.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:WpfApplication10="clr-namespace:WpfApplication10"
    Title="Window1" Height="300" Width="300">
    <WpfApplication10:UserControl1
        MyImageSource="c:\test.png" >        
    </WpfApplication10:UserControl1>
</Window>

third the code behind the usercontrol

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace WpfApplication10
{
    public partial class UserControl1 : UserControl
    {
        public static readonly DependencyProperty MyImageSourceProperty =
            DependencyProperty.Register("MyImageSource", 
                 typeof(BitmapImage),typeof(UserControl1),
                 new FrameworkPropertyMetadata((BitmapImage)new BitmapImage(),
                      FrameworkPropertyMetadataOptions.None
                 ));

        public BitmapImage MyImageSource
        {
            get { return (BitmapImage)GetValue(MyImageSourceProperty); }
            set { SetValue(MyImageSourceProperty, value); }
        }


        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

I know that the Type BitMapImage (of the DP) doesnt work in this way, but i want to know how to implement this feature in a clean, typesave way. I want to reach the same behaviour like the original Image.Source implementation.

thanks in advance, Scott

+1  A: 

You need to create a converter. since your DP defined to be Bitmapimage and in XAML you bind it to string.

Maybe you can find suitable converter here. http://www.codeplex.com/wpfconverters

or try to google "WPF converters"

public object Convert(object value, Type targetType,
                      object parameter, CultureInfo culture)
{
    try
    {
        return new BitmapImage(new Uri((string)value));
    }
    catch 
    {
        return new BitmapImage();
    }
}

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

}

and let your MyImageSource be typeof string. Then you can use converter inside UserControl definition.

Trickster
Yes, this would work.But my real question is: How is the Image.Source implemented.This property works in the way i want.
Scott Olson
may be this link will be useful http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverterattribute.aspx
Trickster
I prefer the comment over your answer. TypeConverters are the way to enable you to set values to non-string properties via a string representation. The answer describes IValueConverter, which may work out in this case, but are not analog to the image.source implementation.
Simpzon
Hi Simpzon, do you know how Image.Source is implemented ??
Scott Olson
Hi Scott, I must admit I don't know it exactly, but when a non-string property is initialized from a string then usually some TypeConverter does this conversion (except if there is an IValueConverter defined in the binding). The TypeConverter is either defined as an attribute on the property or in the type of the property (as in URI for example).
Simpzon
+1  A: 

In your control, name your Image as:

<Image x:Name="someImage" Source="{Binding Path=MyImageSource}" ></Image>

Implement your dependency property as Uri:

public static readonly DependencyProperty MyImageSourceProperty =
    DependencyProperty.Register("MyImageSource", 
     typeof(Uri),typeof(UserControl1),
     new FrameworkPropertyMetadata(new PropertyChangedCallback(OnImageSourceChanged)));

And in OnImageSourceChanged:

private static void OnImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    UserControl1 userControl = (UserControl1)sender;

    userControl.someImage.Source = new BitmapImage((Uri) e.NewValue);
}

This way, you can supply a string path to the dependency property which will be converted to Uri automatically.

EDIT: In Image, the source property is implemented as ImageSource instead of Uri (an abstract class, from which your implementation, i.e. BitmapSource, also derives). It also implements a OnSourceChanged event just like I have implemented one for Uri. The conclusion is, that you will have to use a change event if you want to set the source of an image.

Yogesh
Hi Yogesh, this is really a nice workaround. Thanks a lot.
Scott Olson