Silverlight : afficher des données provenant d’un service WCF dans une grille DataGrid#

Le titre de l’article est assez explicite, on va afficher des données provenant d’un service WCF dans un DataGrid. Cet article va servir d’introduction pour la suite des articles autour de Silverlight.

Les données

On va créer une table Task qui va contenir des tâches, voici le script :

create table Task(id int IDENTITY, 
                [name] varchar(255), 
                comment varchar(1000), 
                realizationDate DateTime, 
                termDate DateTime, 
                reminderDate DateTime,
                concerned varchar(100),
                realized bit default 0
                )

Le service WCF

On va créer un service WCF et à l’aide d’entity framework (pour un souci de rapidité) on va chercher la liste des tâches dans la base de données et la renvoyer.

Créer un nouveau projet « WCF Service Project » et nommez le NavigationAppServices. Nommez la solution que vous allez créer « NavigationApp ».

Dans ce projet créez un nouveau « WCF Service » et nommez le « TasksService », et dans ce projet, créez un répertoire DataAccess.

Dans ce répertoire créer un nouveau « ADO.NET entity data model » et nommez le « DbModel ». N’oubliez pas de cocher la table Task qu’on vient de créer. Ceci va vous générer le modèle Entity Framework avec l’entité Task. (Si vous avez besoin de plus de détails sur cette partie je vous recommande ce post)

Revenons maintenant à notre service TasksService et rajoutons le using et la méthode suivante :

using NavigationAppServices.DataAccess;

public List<Task> GetList() 
{
      DbEntities entities = new DbEntities();
      return entities.Task.ToList<Task>();
}

Dans l’interface ITasksService n’oubliez pas de déclarer la méthode comme suit:

[OperationContract]
List<Task> GetList();

Alors juste une petite mise en garde, ce service que nous avons créé en 30 secondes ne respecte aucun best practice du développement N-Tiers mais pour le besoin de cet article ça suffit amplement.

L’application Silverlight

On y est, maintenant qu’on a préparé le terrain, on va pouvoir accéder à ce service WCF et afficher la liste des tâches dans une grille. Pour ce faire, dans la même solution qui contient les services, créez tout d’abord un projet de type « Silverlight navigation application » et nommez le « NavigationApp ». (Pour comprendre la coquille vide que vous génère Visual studio dans ce cas reportez vous à ce post)

Visual studio va alors nous créer une coquille vide. On va ignorer cette coquille et garder uniquement le point d’entrée de notre application qui est App.xaml pour construire notre application Silverlight.

Positionnez vous au niveau du projet NavigationApp et créez un nouveau « Silverlight User Control » en le nommant MasterPage.xaml ( Nous l’avons nommé comme cela juste parce que ça sera le conteneur de notre application Silverlight mais le fonctionnement n’est pas du tout pareil)

image

Dans le fichier App.xaml.cs remplacez la ligne suivante :

this.RootVisual = new MainPage();

par celle la :

this.RootVisual = new MasterPage();

L’application va donc au démarrage charger notre conteneur au lieu de charger le conteneur généré par Visual Studio. Si vous lancez l’application à ce stage vous aurez une page blanche puisque MasterPage ne contient rien.

Nous allons maintenant travailler sur l’aspect général de l’application, pour cela nous allons définir une grille qui nous permettra d’organiser un peu l’interface et positionner nos différents éléments graphique. Ouvrez MasterPage.xaml et en dessous de cette ligne :

<Grid x:Name="LayoutRoot" Background="White">

Placez ces quelques lignes qui permettent de définir la grille

<Grid.RowDefinitions>
      <RowDefinition Height="50"></RowDefinition>
      <RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
      <ColumnDefinition Width="100"></ColumnDefinition>
      <ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>

Rien de sorcier, nous avons définit une grille avec 2 lignes et 2 colonnes.

Nous allons maintenant remplir les cases de la grille avec des éléments graphiques.

<Border Style="{StaticResource MyBannerStyle}">
      <TextBlock Text="Mon application de la mort"></TextBlock>
</Border>
<Border Style="{StaticResource MyToolboxStyle}">
</Border>
<Border Style="{StaticResource MyBodyPageStyle}">
</Border>

Border est un conteneur graphique permettant de regrouper d’autres éléments. Donc on a définit 3 éléments de type border :

- Le premier sera notre bannière et occupera toute la première ligne de la grille

- Le deuxième sera un panel à gauche de l’écran qui restera vide jusqu’à la fin de cet article mais qui est destiné à accueillir une boite à outils ou un menu.

- Le troisième et dernier va accueillir notre application Silverlight

Les styles qui sont appliqués à ces éléments graphiques sont les suivants :

<Style x:Key="MyBannerStyle" TargetType="Border">
        <Setter Property="Background" Value="#C0C0C0"></Setter>
        <Setter Property="Grid.Row" Value="0"></Setter>
        <Setter Property="Grid.Column" Value="0"></Setter>
        <Setter Property="Grid.ColumnSpan" Value="2"></Setter>
</Style>
<Style x:Key="MyToolboxStyle" TargetType="Border">
     <Setter Property="Background" Value="#C0C0C0"></Setter>
     <Setter Property="Grid.Row" Value="1"></Setter>
     <Setter Property="Grid.Column" Value="0"></Setter>
</Style>

<Style x:Key="MyBodyPageStyle" TargetType="Border">
     <Setter Property="Grid.Row" Value="1"></Setter>
     <Setter Property="Grid.Column" Value="1"></Setter>
</Style>

Il faut les rajouter dans /Assets/Styles.xaml.

Dans MasterPage.xaml , positionnez vous maintenant en dessous de cette ligne.

<Border Style="{StaticResource MyBodyPageStyle}">

et rajoutez le code suivant :

<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" Source="/Tasks">                          
                <navigation:Frame.UriMapper>
                    <uriMapper:UriMapper>
                        <uriMapper:UriMapping Uri="" MappedUri="/Views/Tasks.xaml"/>
                        <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
                    </uriMapper:UriMapper>
                </navigation:Frame.UriMapper>
</navigation:Frame>

Pas de panique, il vous manque des briques, positionnez vous en dessous de cette ligne

xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml

et rajoutez les 2 lignes suivantes :

xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"

Ce code définit la zone qui va accueillir les pages Silverlight. (Pour en savoir plus à propos de l’uri mapping je vous recommande ce post

Créons maintenant notre page Tasks, positionnez vous au niveau du répertoire Views et ajouter une nouvelle « Silverlight page » et nommez la Tasks.xaml.

image

Dans Tasks.xaml, on va tout d’abord définir une Grille pour placer la DataGrid et un petit bouton de rafraîchissement. La grille aura 1 ligne et 2 colonnes, voici son code :

<Grid.RowDefinitions>
    <RowDefinition Height="*"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
     <ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>

Avant de créer la DataGrid qui va contenir la liste des tâches, allons déjà récupérer la liste des tâches à partir de notre service web, on va essayer de faire les choses à peu près proprement avec le pattern MVVM, on ne va pas s’attarder sur ce pattern qui fera l’objet d’un prochain post mais sachez juste que si vous vous intéressez à Silverlight ou wpf, le pattern MVVM est incontournable.

Dans le projet NavigationApp créez 2 nouveaux répertoires et nommez les « Model » et « ViewModel ».

Dans le répertoire Model, créez une nouvelle classe et nommez la « Task.cs », voici son contenu :

public class Task
{
        public int Id { get; set; }

        public string Name { get; set; }

        public bool Realized { get; set; }
}

Donc on a dans notre Model une classe Task qui représente une petite partie de la classe Task exposée par le service.

Dans le répertoire ViewModel, créez une nouvelle classe et nommez-la « TasksViewModel.cs ». Cette classe va contenir les propriétés sur les quels on va lier les composants graphiques de l’interface TasksViewModel. Pour pouvoir notifier les composants graphiques que le contenu des propriétés a changé il faut que notre classe implémente l’interface INotifyPropertyChanged. Pour cela il faut déclarer dans la classe le delegate PropertyChanged de cette manière :

public event PropertyChangedEventHandler PropertyChanged;

On a rajouté la méthode RaisePropertyChanged permettant de déclancher l’évènement PropertyChanged sur une propriété.

Notre grille va se lier à une liste de tâches, donc on va rajouter cette propriété :

private List<Task> tasks;
public List<Task> Tasks 
{
       get { return tasks; }
       set 
       {
            tasks = value;
            RaisePropertyChanged("Tasks");
       }
}

Nous remarquons bien que dans le set on déclanche l’évènement PropertyChanged dès qu’on a modifié le contenu de la propriété.

Et enfin on va aussi rajouter la méthode qui va contacter le service pour ramener les données (FillTasks) et le délégé (taskServiceClient_GetListCompleted) qui va traîter la réponse asynchrone du service et qui va modifier le contenu de la liste Tasks.

Au final voici le code de la classe TasksViewModel :

    public class TasksViewModel : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public void FillTasks() 
        {
            Services.Tasks.TasksServiceClient taskServiceClient = new NavigationApp.Services.Tasks.TasksServiceClient();
            taskServiceClient.GetListCompleted += new EventHandler<NavigationApp.Services.Tasks.GetListCompletedEventArgs>(taskServiceClient_GetListCompleted);
            taskServiceClient.GetListAsync();
        }

        void taskServiceClient_GetListCompleted(object sender, NavigationApp.Services.Tasks.GetListCompletedEventArgs e)
        {
            List<Task> resultTasks = new List<Task>();

            foreach(NavigationApp.Services.Tasks.Task t in e.Result)
            {
                Task mt = new Task();
                mt.Id = t.id;
                mt.Name = t.name;
                if (t.realized.HasValue)
                    mt.Realized = t.realized.Value;
                resultTasks.Add(mt);
            }

            this.Tasks = resultTasks;
        }

        private List<Task> tasks;

        public List<Task> Tasks 
        {
            get { return tasks; }
            set 
            {
                tasks = value;
                RaisePropertyChanged("Tasks");
            }
        }
    }

Il ne nous reste qu’à ajouter la grille et le bouton à l’interface dans Tasks.xaml

<Data:DataGrid x:Name="TasksGrid" Style="{StaticResource MyGridStyle}" ItemsSource="{Binding Tasks}">
</Data:DataGrid>
<Button x:Name="btnRefreshGrid" Click="btnRefreshGrid_Click" Style="{StaticResource MyButtonStyle}" Content="Refresh">
</Button>

Concentrons nous un peu sur le bout de code de la grille et plus particulièrement sur la valeur de l’attribut ItemSource {Binding Tasks}. Cette valeur permet de lier notre grille à l’attribut Tasks de l’objet du DataContext courant. Le DataContext est une propriété de type à la quelle on peut lier (Binding) des composants graphiques, qui contient en général une instance de l’objet qui va peupler nos composants graphiques et qui est hérité par tous les composants graphiques enfants tant qu’il n’est pas redéfini au niveau du composant en lui-même. Nous aurons l’occasion de revenir dessus plus en détail dans un prochain post.

Ajouter les styles suivants au niveau de Styles.xaml :

<Style x:Key="MyGridStyle" TargetType="Data:DataGrid">
        <Setter Property="Grid.Row" Value="0"></Setter>
        <Setter Property="Grid.Column" Value="0"></Setter>
</Style>
<Style x:Key="MyButtonStyle" TargetType="Button">
        <Setter Property="HorizontalAlignment" Value="Left"></Setter>
        <Setter Property="MaxWidth" Value="100"></Setter>
        <Setter Property="Grid.Row" Value="1"></Setter>
        <Setter Property="Grid.Column" Value="0"></Setter>
</Style>

Ajouter l’espace de noms System.Windows.Controls au niveau de Styles.xaml et Tasks.xaml

xmlns:Data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

Dans Tasks.xaml.cs, positionnez vous dans le constructeur et ajouter le code suivant :

TasksViewModel tasksvm = new TasksViewModel();
this.DataContext = tasksvm;
tasksvm.FillTasks();

Tout ce qu’on fait ici c’est dire que le DataContext de la classe Tasks est une nouvelle instance de notre ViewModel et on rempli la propriété Tasks. Vu qu’on a lié notre grille à la proprété Task, lorsque cette dernière sera remplie et donc modifiée elle déclanchera l’évènement PropertyChanged et le moteur de binding va rafraîchir le contenu de la grille.

Et enfin, rajouter cette méthode dans la classe Tasks dans Tasks.xaml.cs qui va s’exécuter lors du click du bouton pour rafraîchir le contenu de la grille.

private void btnRefreshGrid_Click(object sender, RoutedEventArgs e)
{
        ((TasksViewModel)this.DataContext).FillTasks();
}

Vous pouvez maintenant éxecuter, vous devriez avoir quelque chose qui ressemble à ça (n’oubliez pas de remplir la base J)

Vous pouvez aussi modifier le contenu de la table et cliquer sur le bouton rafraîchir qui va mettre à jour la propriété Tasks, cette mise à jour va être notifiée au moteur de binding qui va redessiner la grille.

image

Une dernière explication par rapport à la grille, vous avez certainement remarqué qu’il y a bien 3 colonnes qui correspondent bien aux 3 proriétés de la classe Task. Mais ce qu’il faut surtout remarquer c’est que la colonnes « Realized » a été automatiquement dessinée sous forme de checkbox. En effet, par défaut le DataGrid s’adapte au type de la donnée qu’il affiche et ceci en associant à chaque type un DataTemplate par défaut.

Conclusion

A travers cet exemple basqiue on a introduit plusieurs notions sur les quels on va revenir plus en détail dans de prochains postes :

- Le DataContext et le databinding

- Le pattern MVVM

- Le DataGrid

- Les styles

A très bientôt ;)

Monday, October 26, 2009 10:57:48 AM (Romance Standard Time, UTC+01:00) #    Comments [2]  | 

 

Silverlight 3 : analyse d’un projet « Silverlight navigation application »#

Pour ceux qui se demandent comment marche Silverlight et par quel bout prendre la chose, cet article est fait pour vous. Dans cet article on va analyser la coquille vide créée par Visual Studio pour bien comprendre les mécanismes mis en évidence dans le projet exemple.

Nous allons commencer par créer un projet de type « Silverlight navigation application » (Si vous avez besoin d’aide, reportez vous à ce post)

Concentrons nous maintenant sur la solution générée, qui doit avoir cette allure :

image

Nous avons donc 2 projets :

- NavigationApp.web : application web qui va contenir notre application Silverlight.

- NavigationApp : notre application silverlight

NavigationApp.web

Le projet est une application web, nous remarquons les deux pages de tests suivantes : NavigationAppTestPage.aspx NavigationAppTestPage.html. Ces deux pages mettent en œuvre l’hébergement de l’application Silverlight NavigationApp.xap en se basant sur le fichier Silverlight.js. Si on ouvre la page html (ou aspx) on va trouver essentiellement la balise Object qui va nous permettre d’inclure notre application Silverlight dans la page.

<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
          <param name="source" value="ClientBin/NavigationApp.xap"/>
          <param name="onError" value="onSilverlightError" />
          <param name="background" value="white" />
          <param name="minRuntimeVersion" value="3.0.40818.0" />
          <param name="autoUpgrade" value="true" />
          <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40818.0" style="text-decoration:none">
               <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/>
          </a>
        </object>

Dans la balise object, nous pouvons définir plusieurs paramètres dont :

- Source : qui est le binaire à télécharger.

- onError : la fonction javascript à executer lorsqu’une exception non catchée est levée au sein de l’application Silverlight.

- backgroung : la couleur de fond de l’application silverlight.

- minRuntimeVersion : La version minimale du plugin silverlight pouvant exécuter le binaire.

- autoUpgrade : Définit une valeur qui indique si une version du plug-in Silverlight antérieure au minRuntimeVersion spécifié tente de se mettre à jour automatiquement.

La liste complète des paramètres que nous pouvons définir pour une balise object est ici, ce qu’il faut retenir c’est que dès que nous voulons changer quelque chose par rapport à l’intégration de l’application ou du plugin silverlight au sein de la page c’est de ce côté ci qu’il faut regarder :)

L’iframe « _sl_historyFrame » est utilisée pour gérer l’histoique de navigation au sein de l’application Silverlight. Elle est partagée par toutes les applications Silverlight dans une même page.

Vous avez certainement remarqué que le fichier Silverlight.js est inclus dans ces pages de test. Ce fichier permet principalement de faire 2 types de fonctionnalités :

- Inclure programmatiquement une application Silverlight.

- Améliorer la procédure d'installation ou de mise à niveau standard de Silverlight.

Vous trouverez ici la liste des fonctions que propose ce fichier js.

Je pense qu’on a fait le tour de l’application web, tournons nous maintenant vers l’application Silverlight.

NavigationApp

C’est le projet qui contient notre application silverlight. Le point d’entrée de cette application est le fichier App.xaml, donc commençons déjà par analyser ce fichier. Son contenu devrait ressembler à ça :

<Application   
  x:Class="NavigationApp.App"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Assets/Styles.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>

</Application>

On voit tout de suite que c’est une application avec la balise <Application>. Dans ce fichier on va définir toutes les ressources au niveau de l’application, ici à titre d’exemple, la ressource est un fichier xaml contenant tous les styles de l’application.

Dans le code behind de l’App.xaml on s’abonne aux évènements « Startup » et « UnhandledException » en définissant le comportement de l’application lorsque ces deux évènements sont déclanchés.

Lors du démarrage de l’application, l’évènement « Startup » est déclanché, si on regarde le comportement de l’application au Startup nous allons trouver la ligne de code suivante :

this.RootVisual = new MainPage();

A l’aide de cette ligne nous allons instancier notre conteneur d’écrans (pages) qui est ici MainPage.

Allons du coup du côté de MainPage.xaml : La première chose que nous allons remarquer c’est que MainPage est un UserControl, on le voit à l’aide de la balise <UserControl> au tout début du fichier xaml. Mais au fait, comment est chargé le xaml ? parce que ce qu’on a vu c’est qu’on fait un new MainPage(). Si nous regardons le constructeur dans le code behind de Mainpage.xaml nous allons nous apercevoir qu’il y a une méthode qui s’appelle InitializeComponents

En effet, dans le « Solution Explorer », positionnez vous au niveau du projet et cliquer sur l’icône « Show all files » comme suit :

image

Vous allez voir apparaître les répertoires cachés bin et obj. Dans le répertoire obj -> Debug ouvrez le fichier qui s’appelle MainPage.g.cs. Vous allez y trouver la méthode InitializeComponents que nous cherchions. Dans cette méthode nous allons charger le xaml et tous ces contrôles. Vous trouverez un fichier .g.cs pour chaque xaml que vous créez dans votre projet.

Retournons à notre xaml MainPage maintenant, nous avons dit qu’il contient une balise <UserControl> qui disait que MainPage était un UserControl, cette balise contient quelques attributs lui pêrmettant de charger les espaces de noms de librairies comme Navigation ou Control … Ensuite on trouve 2 grandes parties :

1 - Navigation frame

 

<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}" 
                              Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">
                <navigation:Frame.UriMapper>
                  <uriMapper:UriMapper>
                    <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>
                    <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
                  </uriMapper:UriMapper>
                </navigation:Frame.UriMapper>
            </navigation:Frame>

Navigation frame va acceuillir une navigation page qui sera définie par la logique d’uri mapping. En fait notre UserControl MainPage joue le rôle de conteneur comme une MasterPage en ASP.NET : nous allons mettre dedans l’allure générale que doivent avoir nos pages et nous allons définir les zones (Navigation frame) dans les quelles nous allons acceuillir des navigation pages.

L’uri mapping, permet de faire le mapping entre l’url demandée et la page délivrée au client. Regardons tout d’abord la balise <navigation:Frame> qui est caractérisée par les attributs suivants :

- x:Name : le nom du contrôle

- Style : son style (Styles.xaml)

- Source : l’Uri par défaut

- Navigated : définit ce que doit faire l’application après qu’on ai navigué vers une page

- NavigationFailed : définit ce que doit faire l’application lorsque la navigation vers une page échoue

Ici nous définissons quelques règles de mapping d’uri en disant que si la page demandée est vide (Uri= «») donc l’url demandée ressemble à celle-ci : http://mondomaine/NavigationAppTestPage.aspx la navigation frame va alors contenir la page par défaut qui est /Views/Home.xaml. Et si la page demandée est /{PageName} la navigation frame va alors contenir la page /Views/{PageName}.xaml. Essayons maintenant d’analyser notre situation de départ en démarrant le projet, nous allons lancer la page NavigationAppTestPage.aspx et le navigation frame va demander l’Uri « /Home » définie dans l’attribut « Source » de la balise « navigation :Frame ». l’Uri /Home va donc être mappée à /Views/Home.xaml grâce à cette règle :

<uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>

et la navigation frame va donc contenir la page Home.xaml.

2- Banière

        <Grid x:Name="NavigationGrid" Style="{StaticResource NavigationGridStyle}">

            <Border x:Name="BrandingBorder" Style="{StaticResource BrandingBorderStyle}">
                <StackPanel x:Name="BrandingStackPanel" Style="{StaticResource BrandingStackPanelStyle}">

                    <ContentControl Style="{StaticResource LogoIcon}"/>
                    <TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}" 
                               Text="Application Name"/>

                </StackPanel>
            </Border>

            <Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
                <StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">
                    <HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}"
                                   NavigateUri="/Home"   TargetName="ContentFrame" Content="home"/>
                                     
                    <Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>

                    <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}" 
                                     NavigateUri="/About" TargetName="ContentFrame" Content="about"/>

                </StackPanel>
            </Border>
        </Grid>

Ce code permet de dessiner la banière qu’il y a en haut avec le logo, le nom de l’application et les boutons, nous n’allons pas nous attarder sur cette partie parce que c’est uniquement l’utilisation de composants graphique.

Le répertoire /Views

Concentrons nous tout d’abord sur Home.xaml et About.xaml. Ces deux fichiers sont de type navigation page. Les navigation pages est un apport de la version 3 de Silverlight. En fait, Silverlight 3 embarque un framework de navigation et du coup nous pouvons désormais naviguer entre les pages xaml d’une application Silverlight en utilisant le navigateur.

Il ne nous reste plus qu’à jeter un coup d’œil sur la page ErrorWindow.xaml qui est dans le répertoire Views. Cette page est de type childWindow, dans la terminologie web c’est une popup.

Résumé

Voila voila, l’analyse du projet exemple est finie, nous avons vu :

- Que App.xaml est le point d’entrée de l’application Silverlight.

- Que dans App.xaml nous pouvons définir les ressources de l’application.

- Dans App.xaml.cs, nous définissons notre UserControl conteneur en faisant this.RootVisual= new MainPage() dans le code behind de App.xaml.

- Dans MainPage.xaml nous définissons l’ossature de l’application (un peu comme une Master Page) et les zones (Navigation Frame) qui peuvent acceuillir du contenu(Navigation Pages).

- Que dans une Navigation frame nous pouvons définir l’uri mapping.

- Les pages Home et About sont de type Navigation Page et sont hébergés par une navigation frame.

- Silverlight 3 embarque un framework de navigation permettant de naviguer entre les pages d’une application silverlight.

- Une ChildWindow est l’équivalent d’une popup dans le monde web.

Il reste néanmoins énormément de choses à voir comme les composants graphiques, comment accéder aux données serveur (puisqu’on est côté client), Les dependency proporty et attached property, DataBinding, … nous allons essayer de couvrir tous ces points dans de prochains posts.

Tuesday, October 20, 2009 8:19:00 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Windows phones sont là!!!#

Juste un petit mot pour vous dire que comme annoncé par Microsoft les Windows phones sont sortis aujourd’hui le 6 octobre un peu partout dans le monde. Voici une petite vidéo pour vous mettre l’eau à la bouche. SFR quand à elle annonce que le Windows phone sera vendu à partir du 7 octobre. Les windows phone vont embarquer un Windows mobile 6.5 avec la gesture API pour toutes les manipulations aux doigts, une ergonomie affinée et un allègement de tout l’OS.

Enjoy ;)

Tuesday, October 06, 2009 8:40:00 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

Instancier une classe générique avec un type dynamique et appeler une méthode appartenant à cette classe.#

J’ai rencontré ce problème en développant une couche d’accès aux données générique avec le compact framework. Voici le problème : J’ai développé une classe générique CRUD<T> qui permet de faire du CRUD simple. Pour ça j’ai utilisé les attributs pour décorer mes propriétés d’entités et dire que telle classe correspond à telle table et que telle propriété correspond à tel champ dans cette table. Ensuite et à l’aide de System.Reflection on regarde les attributs de la classe et des propriétés, on génère le sql correspondant à l’entité passée en paramètre et on exécute de la base.

Bon tout ça marche bien, maintenant supposons que l’on ait la classe suivante :

    public class Personne
    {

        int id;

        List&lt;Voiture&gt; Voitures;

    }

Il faudrait donner la possibilité d’auto charger les voitures d’une personne au même moment qu’on charge une personne. Donc on rajoute un attribut sur la propriété de type List<Voiture>dans la classe Personne pour dire que c’est une entité liée et en parcourant les attributs de ma classe pour générer le sql, quand je rencontre ce type d’attribut, je voudrais rappeler ma classe CRUD<T> avec T = Voiture pour obtenir la liste de voitures correspondantes à la personne. Or on ne sait pas par avance que c’est des Voitures ce n’est qu’au Runtime que je saurais que c’est des voitures donc le problème est le suivant : invoquer ma classe CRUD<T> avec un T dynamique.

Pour ce faire il y a 2 solutions ou plutôt 2 types de solutions :

- Contourner le problème en disant par exemple que de toutes les façons que c’est nul de vouloir auto charger les liens et de laisser ça à la demande du développeur.

- Utiliser ce qui existe dans le compact framework pour réussir

Je me suis plutôt focalisé sur le 2ème type de solution même si je ne suis pas en désaccord total avec le 1er type.

On dispose donc d’une variable « typeVoiture » de type « Type » qui contient le type « Voiture »

Pour créer le type CRUD<Voiture> on a à notre disposition dans Type la méthode MakeGenericType, on peut donc procéder de la manière suivante :

Type crud = typeof(CRUD&lt;&gt;);
Type[] typeArgs = { typeVoiture }; 
Type repositoryType = crud.MakeGenericType(typeArgs);

Et pour en créer une instance il suffit d’utiliser Activator.CreateInstance de la manière suivante :

object repository = Activator.CreateInstance(repositoryType);

On remarque que notre instance est de type « object », on ne peut donc pas utiliser directement ses méthodes et on ne peut pas le caster non plus puisqu’on ne peut pas écrire CRUD<typeVoiture.GetType()>.

Le seul moyen (que je connaisse en tout cas) est le suivant : On construit un objet de type « MethodInfo » à partir de l’instance de type générique qu’on a créé précédemment. Ensuite, on construit un tableau d’object qui correspond aux paramètres de la méthode à appeler et enfin on l’appelle en utilisant la méthode Invoke.

MethodInfo genericMethod = repositoryType.GetMethod("GetByForeignKey"); paramList = new object[2]; paramList[0] = param1; paramList[1] = param2;

genericMethod.Invoke(repository, paramList);

SI vous connaissez un autre moyen de faire, ou si vous voulez juste réagir, nhésitez pas, commentez ce post ;)

Thursday, October 01, 2009 9:43:25 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

All content © 2012, Zied Nemili