Silverlight 2: binding d'une combobox vers des images sérialisées en byte[] depuis WCF

Ayant presque terminé une longue série d'articles autour de ces sujets, je vais en profiter pour également faire quelques petits posts autour de certains points. En effet, j'ai parfois passé un peu de temps à stresser mes moteurs de recherches favoris dans l'optique d'une solution et j'aimerais bien vous faire économiser ce temps.

L'idée de ce post est de couvrir le scénario suivant:

- utilisation d'un type similaire à:

public class MonTypeAvecImage

{

    public string uneChaineDeDescription { get; set; }

    public byte[] uneImageJpeg { get; set; }

}

- un service WCF vous retournant une collection (List<MonTypeAvecImage>) de vos objets ayant donc pour membre une image sérialisée sous la forme d'un tableau de bits (byte[]). Cela nous donne donc une collection d'images comme source potentielle.

Note importante : n'oubliez surtout pas de sérialiser vos images au format JPEG ou PNG car ce sont à l'heure actuelle que les 2 formats d'image supportés par Silverlight 2.

- un client Silverlight 2 accédant à ce service WCF en basic HTTP et disposant, entre autres, d'une combobox devant être alimentée par la collection retournée par le service WCF pour afficher l'image suivi du texte de description.

Par défaut, en faisant l'ajout de référence au service WCF, le type List<MonTypeAvecImage> sera reconstruit dans le proxy client sous la forme de ObservableCollection<MonTypeAvecImage>. De ce coté là, c'est parfait.

En WPF, il est très simple de gérer le binding vers la source d'un élément de type image si cette source est un tableau de bits. WPF va en effet automatiquement construire pour vous l'image à partir du type byte[]. En Silverlight 2, ce n'est pas le cas. Il va falloir passer par un convertisseur qui va transformer le type byte[] vers BitmapImage qui ira lui correctement alimenter la source de l'image du monde Silverlight.

Pour cela, je vous propose le code C# suivant:

public class ConvertImage : IValueConverter

{

    #region IValueConverter Members

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        throw new NotImplementedException();

    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        if (value == null)

            return null;

        BitmapImage img = new BitmapImage();

        using (MemoryStream stream = new MemoryStream((byte[])value))

        {

            img.SetSource(stream);

        }

        return img;

    }

    #endregion

}

Ajoutez alors ce convertisseur comme ressource à votre page Silverlight:

<UserControl.Resources>

    <local:ConvertImage x:Key="ConvertImage" />

</UserControl.Resources>

Et voici alors un exemple d'utilisation avec une ComboBox coté XAML:

<ComboBox x:Name="maSuperCombobox">

    <ComboBox.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Horizontal" Margin="2">

                <Image Width="100" Source="{Binding uneImageJpeg, Converter={StaticResource ConvertImage}}"/>

                <TextBlock Margin="5" Width="75" Text="{Binding uneChaineDeDescription}"/>

            </StackPanel>

        </DataTemplate>

    </ComboBox.ItemTemplate>

</ComboBox>

En n'oubliant évidement pas d'alimenter au préalable la propriété ItemsSource de la combobox maSuperCombobox dans le code C# avec la collection de type ObservableCollection<MonTypeAvecImage> retournée par le service WCF.

Dans l'article que j'ai écrit, cela me donne le résultat suivant:

image

David