Silverlight 2 – Binding Images to Uri’s

This came via Mike who was playing with some Silverlight sample but I thought it was worth sharing.

Say I’ve got this really simple piece of UI in Silverlight;

<UserControl x:Class="SilverlightApplication2.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:SilverlightApplication2"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
    <Grid.Resources>
      <local:DataClass x:Key="dataContext"/>
    </Grid.Resources>
      <Image
      Source="{Binding MyUri}"
        DataContext="{StaticResource dataContext}"/>
  </Grid>
</UserControl>

and I’ve got this code that lives behind it;

namespace SilverlightApplication2
{
  public class DataClass
  {
    public Uri MyUri
    {
      get
      {
        return (new Uri("Images/img1.jpg", UriKind.Relative));
      }
    }
  }
  public partial class Page : UserControl
  {
    public Page()
    {
      InitializeComponent();
    }
  }
}

All looks fine – we have our Source on our image bound to a property called MyUri on an instance of the type DataClass and that instance is created declaratively from XAML.

However, it doesn’t work and I think it’s because we are binding a property of type ImageSource ( the Source property on Image ) to a property of type Uri and there’s no natural converter. This is initially a bit odd because if we change the type of our property MyUri to be a string then that’ll just naturally work. So, we need a converter. The hackiest one we could implement might look like;

  public class UriToImageSourceConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      // No checks...
      return (new BitmapImage((Uri)value));
    }

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

and then I can tweak my XAML to be something like;

<UserControl x:Class="SilverlightApplication2.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:SilverlightApplication2"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
    <Grid.Resources>
      <local:DataClass x:Key="dataContext"/>
      <local:UriToImageSourceConverter
        x:Key="uriToImageConverter" />
    </Grid.Resources>
      <Image
      Source="{Binding MyUri,Converter={StaticResource uriToImageConverter}}"
        DataContext="{StaticResource dataContext}"/>
  </Grid>
</UserControl>

and we’re back in business.