Introduction à Silverlight 2
Date de publication : 27/01/2008
Par
Benjamin Roux (Retour aux articles)
(2 commentaires)
Cet article est une introduction à Silverlight 2.
1. Introduction
2. Création du projet
3. Première application
4. Le positionnement
4-1. Canvas
4-2. StackPanel
4-3. Grid
5. Utiliser le réseau pour récupérer des infos et remplir un DataGrid
6. Les Styles
7. ListBox et DataBinding
8. UserControls
9. Les Templates
10. De Silverlight à WPF
11. L'application en ligne
12. Conclusion
13. Remerciements
1. Introduction
Silverlight est l'une des nouvelles technologies nées de chez Microsoft.
Avec, il est possible de créer des applications web riches, des animations, des jeux…
Silverlight se décline actuellement en 2 versions :
- 1.0 qui permet de faire des applications côté client, tout est en Javascript.
- 2 (anciennement 1.1) qui intègre une version du Framework .NET avec une CLR et qui permet donc d'exécuter du code C# ou VB.NET.
Dans cet article nous apprendrons donc comment utiliser la version 2.
Quelques outils sont requis pour développer en Silverlight 2.
Les outils requis :
Une fois tous ces outils installés nous pouvons commencer.
2. Création du projet
Tout d'abord on lance Visual Studio 2008 et on crée un nouveau projet de type Silverlight Application.
Une fois le nom du projet entré, on a le choix entre créer un nouveau projet de type WebSite directement dans notre solution, ou de simplement avoir une page HTML.
Pour notre article j'ai sélectionné la seconde option.
Nous voici donc avec notre projet fraichement créé.
On peut donc aperçevoir un mode splité pour notre XAML ce qui est assez agréable. Puis on peut voir les différents fichiers crées par défaut.
Fini donc les fichiers HTML ou JS, nous avons seulement 2 fichiers XAML (avec leur .cs correpondant pour le code-behind).
- Page.xaml : notre XAML principal, contient le code de notre application, le code-behind sert pour le code des évènements par exemple
- App.xaml : contient les Ressources de notre application (les styles par exemple), le code-behind lui sert à manipuler les évènements au niveau de l'application
(Application_Startup, Application_Exit...).
Là on peut se demander où est donc notre fameux fichier HTML, c'est simple il se trouve dans le répertoire ClientBin.
Un petit coup d'oeil à la ToolBox où on peut voir toute une tripotée de contrôle qui vont donc nous changer la vie par rapport à la version 1.0 et 1.1 alpha. Bref que du bon.
3. Première application
Une fois notre projet crée, on va créer notre première application.
On va donc simplement rajouter un bouton qui change de texte lorsque l'on clique dessus.
 |
Remarquons l'Intellisense.
|
Ici on peut voir la création automatique d'EventHandler (qui n'était pas présente dans la version alpha). Si on clique dessus notre EventHandler est créé
dans notre Page.xaml.cs.
Voici donc le code XAML final.
<UserControl x:Class="TestSilverlight2.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="Green">
<Button x:Name="myButton" Content="Click me !" Click="myButton_Click" Width="100" Height="50"></Button>
</Grid>
</UserControl>
|
Un petit tour dans le Page.xaml.cs pour rajouter notre code-behind.
private void myButton_Click(object sender, RoutedEventArgs e)
{
myButton.Content = "You clicked !";
}
|
Voici le résultat visuel.
Une fois qu'on a cliqué dessus.
Et voici donc notre première application en Silverlight 2.
4. Le positionnement
Nous voici donc dans la seconde partie sur le positionnement.
Silverlight 2 inclut 3 des systèmes de positionnement de WPF.
4-1. Canvas
Le Canvas était le système de positionnement utilisé dans Silverlight 1.0 et 1.1.
Tous les éléments dans un Canvas sont positionnés par 2 propriétés : Canvas.Left et Canvas.Top.
<UserControl x:Class="TestSilverlight2.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas x:Name="LayoutRoot" Background="Green">
<Button Content="Bouton 1" Width="100" Height="50" Canvas.Left="10" Canvas.Top="10"/>
<Button Content="Bouton 2" Width="100" Height="50" Canvas.Left="40" Canvas.Top="100"/>
</Canvas>
</UserControl>
|
Le résultat.
4-2. StackPanel
Le StackPanel permet de positionner les éléments les uns en dessous des autres (ou les uns à côté des autres).
<UserControl x:Class="TestSilverlight2.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel x:Name="LayoutRoot" Background="Green">
<Button Content="Bouton 1" Width="100" Height="50" Margin="20"/>
<Button Content="Bouton 2" Width="100" Height="50" Margin="20"/>
</StackPanel>
</UserControl>
|
Le résultat.
Comme vous pouvez le voir dans le code, l'écart entre les éléments est spécifié par la propriété Margin.
On peut également changer l'orientation via le propriété Orientation.
<UserControl x:Class="TestSilverlight2.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel x:Name="LayoutRoot" Background="Green" Orientation="Horizontal">
<Button Content="Bouton 1" Width="100" Height="50" Margin="20"/>
<Button Content="Bouton 2" Width="100" Height="50" Margin="20"/>
</StackPanel>
</UserControl>
|
4-3. Grid
Et voici le positionnement de type Grid.
Le Grid et le système de positionnement le plus flexible il est basé sur des lignes et des colonnes, il est conceptuellement proche du tableau HTML.
Il suffit juste de spécifier au contrôle sa colonne ainsi que sa ligne via les propriétés Grid.Column et Grid.Row.
<UserControl x:Class="TestSilverlight2.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="330" Height="180">
<Grid x:Name="LayoutRoot" Background="Green">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="110"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Button Content="Bouton 1" Width="100" Height="50" Grid.Column="0" Grid.Row="0"/>
<Button Content="Bouton 2" Width="100" Height="50" Grid.Column="2" Grid.Row="0"/>
<Button Content="Bouton 3" Width="100" Height="50" Grid.Column="0" Grid.Row="2"/>
<Button Content="Bouton 4" Width="100" Height="50" Grid.Column="2" Grid.Row="2"/>
<Button Content="Bouton 5" Width="100" Height="50" Grid.Column="1" Grid.Row="1"/>
</Grid>
</UserControl>
|

Tout comme les tableaux en HTML, on peut fusionner des colonnes et lignes (pour mettre un contrôle sur 2 lignes par exemples) avec les propriétés
Grid.RowSpan et Grid.ColumnSpan.
5. Utiliser le réseau pour récupérer des infos et remplir un DataGrid
Dans cette partie vous allons voir comment récupérer des informations via le réseau et comment remplir un DataGrid.
Tout d'abord nous allons créer un nouveau projet mais cette fois nous allons aussi créer un projet de type Web Site.
Une fois ceci fait nous allons simplement ajouter une WaterMarkedTextBox (TextBox avec un texte qui disparait lorsque l'on clique dessus), un Button et un GridView dans notre XAML.
On place le tout dans un Grid.
<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="FlickrPhotoViewer.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Flickr="clr-namespace:FlickrPhotoViewer;assembly=FlickrPhotoViewer">
<Grid x:Name="LayoutRoot" Background="#BBF99D">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<WatermarkedTextBox x:Name="textSearch" Watermark="Search..." Grid.Column="0"
VerticalAlignment="Center" Margin="10,10,0,10"/>
<Button x:Name="buttonSearch" Click="buttonSearch_Click" Width="50" Height="20" Content="Get" Grid.Column="1"/>
</Grid>
<my:DataGrid x:Name="Photos" AutoGenerateColumns="True" Grid.Row="1" Margin="10,0,10,10"></my:DataGrid>
</Grid>
</UserControl>
|

Le fait d'avoir enlevé les propriétés Width et Height dans la balise UserControl permet à notre contrôle Silverlight d'être redimensionné
en même temps que la fenêtre.
Ensuite nous allons aller dans le code-behind pour mettre le code du clic sur le bouton.
Pour cet exemple nous allons récupérer des données via l'API de Flickr. Je vais utiliser leur méthode
flickr.photos.search. Pour cela nous allons utiliser une nouveauté
de Silverlight 2, c'est le namespace
System.Net, qui contient la classe
WebClient.
 |
Vous pouvez voir le XML généré par cette méthode ici.
|
private void buttonSearch_Click(object sender, RoutedEventArgs e)
{
string url = string.Format("http://api.flickr.com/services/rest/?method=flickr.photos.search&" +
"api_key=1cb12f30d9a23d70f00e4a238b4cf1fd&text={0}&machine_tag_mode=&per_page=20",
textSearch.Text);
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new Uri(url));
}
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
}
}
|
Maintenant nous allons créer une classe qui représentera une image sur Flickr. On va donc ajouter une nouvelle classe à notre projet et mettre ce code.
public class FlickrPhoto
{
public long Id { get; set; }
public string Owner { get; set; }
public string Title { get; set; }
public string Image { get; set; }
}
|
Nous allons donc stocker l'id, le propriétaire, le titre et l'adresse de l'image. Pour récupérer l'adresse de l'image nous allons utiliser
les infos retournées dans le XML à savoir le farm-id, le server-id, l'id et le secret. En effet les photos peuvent être retrouvées via cette URL :
http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}.jpg
Maintenant nous allons rajouter le code pour exploiter le XML, pour cela nous allons utiliser LINQ donc il faut avant tout ajouter la référence System.Xml.Linq à notre projet.
private void DisplayFlickrPhotos(string xml)
{
XDocument doc = XDocument.Parse(xml);
var photos = from photo in doc.Descendants("photo")
select new FlickrPhoto
{
Id = (long)photo.Attribute("id"),
Owner = (string)photo.Attribute("owner"),
Title = (string)photo.Attribute("title"),
Image = string.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg",
(int)photo.Attribute("farm"),
(int)photo.Attribute("server"),
(long)photo.Attribute("id"),
(string)photo.Attribute("secret"))
};
Photos.ItemsSource = photos;
}
|
On n'oublie pas d'ajouter l'appel à cette méthode à la place du TODO.
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
DisplayFlickrPhotos(e.Result);
}
}
|
Et voici le résultat une fois que l'on a cliqué sur le bouton.
Voilà nous venons de voir qu'il était super simple de faire désormais du Cross Domain, et de jouer avec le XML avec Linq.
Nous allons maintenant améliorer notre GridView, en affichant la photo lorsque l'on clique sur une ligne.
Pour cela nous allons rajouter un Template lorsqu'une ligne est sélectionnée.
<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="FlickrPhotoViewer.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Flickr="clr-namespace:FlickrPhotoViewer;assembly=FlickrPhotoViewer">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<WatermarkedTextBox x:Name="textSearch" Watermark="Search..." Grid.Column="0"
VerticalAlignment="Center" Margin="10,10,0,10"/>
<Button x:Name="buttonSearch" Click="buttonSearch_Click" Width="50" Height="20" Content="Get" Grid.Column="1"/>
</Grid>
<my:DataGrid x:Name="Photos" AutoGenerateColumns="True" RowDetailsVisibility="VisibleWhenSelected"
Grid.Row="1" Margin="10,0,10,10">
</my:DataGrid>
</Grid>
</UserControl>
|
Désormais la photo sera affichée quand on cliquera sur une ligne.
6. Les Styles
Les Styles en Silverlight (et WPF) permettent d'appliquer un style à un ensemble de contrôle à l'instar des fichiers .skin en ASP.NET ou encore des fichiers CSS.
Leur déclaration se fait dans le fichier App.xaml.
<Application.Resources>
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Width" Value="50"/>
<Setter Property="Height" Value="20"/>
</Style>
</Application.Resources>
|
Ici tous les boutons auxquels j'applique ce style auront une largeur de 50 et une hauteur de 20.
Pour appliquer un style c'est extrêment simple. Il suffit de le spécifier dans la propriété Style des contrôles.
<Button x:Name="buttonSearch" Click="buttonSearch_Click" Content="Get" Style="{StaticResource ButtonStyle}"/>
|
7. ListBox et DataBinding
Dans cette partie nous allons voir comment afficher des données dans une ListBox.
Tout d'abord nous allons supprimer notre DataGrid pour le remplacer par une ListBox.
<ListBox x:Name="Photos" Grid.Row="1"></ListBox>
|
On lance.
Seulement l'affichage n'est pas top, en effet c'est la méthode ToString() qui est appelée pour afficher les éléments et par défaut
elle affiche le namespace et le nom de la classe. Nous allons donc rendre l'affiche plus joli.
Pour cela nous allons utiliser la propriété DisplayMemberPath pour spécifier quelles propriétés de notre classe FilckrPhoto afficher.
<ListBox x:Name="Photos" DisplayMemberPath="Title">
</ListBox>
|
Si on veut afficher plusieurs éléments (par exemple l'id, le titre et même l'image) alors il faut modifier l'ItemTemplate de notre ListBox.
<ListBox x:Name="Photos" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Style="{StaticResource ThumbnailStyle}"/>
<TextBlock Text="{Binding Title}" Style="{StaticResource TextBlockStyle}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
|
 |
On n'oublie alors pas d'enlever la propriété DisplayMemberPath.
|
Avec les styles suivants.
<Style x:Key="ThumbnailStyle" TargetType="Image">
<Setter Property="Margin" Value="10"/>
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="50"/>
</Style>
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Margin" Value="10"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
|
Chaque item sera donc composé d'une miniature de l'image suivi du titre.
La ListBox supporte la séléction ainsi que le déplacement via les flèches du clavier.
8. UserControls
Dans cette partie nous allons voir comment créer et utiliser un UserControl en Silverlight. Nous allons donc reprendre l'application précédente et rajouter
un panel contenant les informations d'une image lorsque l'on clique sur un item de la ListBox.
On va tout d'abord créer notre UserControl : Add -> New Item
Ajoutons lui quelques contrôles pour afficher le titre, l'image, le propriétaire et le chemin de l'image ainsi qu'un bouton pour cacher le contrôle.
<UserControl x:Class="FlickrPhotoViewer.FlickrPhotoDetail"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel HorizontalAlignment="Center">
<Button x:Name="btnClose" Content="Fermer" Click="btnClose_Click"/>
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleStyle}"/>
<Image Source="{Binding Image}" Style="{StaticResource ImageStyle}"/>
<TextBlock Text="{Binding Owner}" Style="{StaticResource OwnerStyle}"/>
<TextBox Text="{Binding Image}" IsReadOnly="True"/>
</StackPanel>
</Grid>
</UserControl>
|
Voici le code du clic sur le bouton.
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Visibility = Visibility.Collapsed;
}
|
On cachera donc notre UserControl quand on cliquera sur le bouton.
Et voici maintenant les styles.
<Style x:Key="TitleStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="30"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="Margin" Value="10"/>
</Style>
<Style x:Key="ImageStyle" TargetType="Image">
<Setter Property="Margin" Value="10"/>
<Setter Property="Height" Value="300"/>
<Setter Property="Width" Value="300"/>
</Style>
<Style x:Key="OwnerStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontFamily" Value="Verdana"/>
<Setter Property="Margin" Value="10"/>
</Style>
|
Alors comme vous pouvez voir nous utilisons du DataBinding, et vous vous demandez peut-être où est-ce qu'il va aller chercher ses infos. C'est simple
il va aller les chercher dans sa propriété DataContext qui si elle n'est pas définie est celle du contrôle de niveau supérieur. On va donc devoir
spécifier le DataContext de notre UserControl au moment de l'afficher.
Tout d'abord nous allons l'ajouter à notre application.
Pour cela il faut d'abord dire où se trouve notre contrôle et lui donner un namespace. On va donc rajouter cette ligne dans notre Page.xaml dans la balise
UserControl.
xmlns:Flickr="clr-namespace:FlickrPhotoViewer;assembly=FlickrPhotoViewer"
|
On va donc rajouter notre UserControl à notre application, nous allons le placer tout à la fin et faire en sorte qu'il soit sur les 2 lignes de notre Grid.
<Flickr:FlickrPhotoDetail x:Name="PhotoDetail" Grid.RowSpan="2" Visibility="Collapsed"/>
|
On met sa visibilité à Collapsed (caché) par défaut.
Maintenant il ne nous reste plus qu'à l'afficher et définir son DataContext quand on clique sur un item de la ListBox.
On s'abonne donc à l'é