David Rousset - HTML5 & Gaming Technical Evangelist

HTML5 & Gaming Technical Evangelist

Comment développer des applications d’entreprises orientées données avec Silverlight 3 : introduction à .NET RIA Services (3/4)

Comment développer des applications d’entreprises orientées données avec Silverlight 3 : introduction à .NET RIA Services (3/4)

  • Comments 9

Article mis à jour : juillet 2009 pour la sortie de Silverlight 3 RTW et .NET RIA Services Juillet 2009 

Nous avons construit le squelette de notre application dans le 2ème billet. Nous allons ici faire usage de nouveaux contrôles de Silverlight 3 et ajouter une règle de validation coté serveur pour observer comment elle se réplique coté client par la suite.

Utilisation de nouveaux contrôles Silverlight 3

Reprenons notre application. Pour l’instant, vous allez me dire : « c’est bien gentil tout ça mais afficher tous les enregistrements sans pagination, c’est nul ! ». Bon, alors tentons de régler ce différent.

Le contrôle DataSource

Commencez par retirer les quelques lignes de code que nous avions ajoutées dans le code behind : Home.xaml.cs. On va tenter de faire la même chose en pur XAML.

Ajoutez l’utilisation de ces namespaces à votre contrôle :

xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Ria.Controls"
xmlns:domain="clr-namespace:GestionClientsRIA.Web"

Le dernier est l’équivalent du « using » fait en C#. Insérez ce bloc de XAML au début du StackPanel :

<riaControls:DomainDataSource x:Name="source" 
              QueryName="GetCustomers" 
              AutoLoad="True">
    <riaControls:DomainDataSource.DomainContext>
        <domain:CustomersContext />
    </riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>


On indique ainsi que l’on souhaite appeler la méthode GetCustomers depuis le domaine CustomersContext. Il nous reste maintenant à indiquer au contrôle grille où se trouve sa source de données :

<data:DataGrid x:Name="GrilleClients" ItemsSource="{Binding Data, ElementName=source}" />

On utilise donc ici le binding entre éléments, autre nouveauté déjà abordée dans ce précédent billet. Si on exécute l’ensemble, on a bien un résultat identique au code C# avec la méthodeLoad(contexte.GetCustomersQuery()).

Trions maintenant les données par ordre croissant selon le nom de l’entreprise à laquelle le client appartient. Pour cela, ajoutez ce morceau de XAML juste avant la balise fermante </riaControls :DomainDataSource> :

<riaControls:DomainDataSource.SortDescriptors
    <riaData:SortDescriptor PropertyPath="CompanyName" Direction="Ascending" />
</
riaControls:DomainDataSource.SortDescriptors>

Désormais les enregistrements sont bien triés par ordre alphabétique croissant selon le nom de l’entreprise. Mais je n’ai toujours pas répondu au besoin de pagination. J’y arrive, j’y arrive…

Le contrôle DataPager

Dans le StackPanel où se trouve le contrôle DataGrid, ajoutez ce XAML en dessous de la grille de données :

<data:DataPager PageSize="10" Source="{Binding Data, ElementName=source}" />

On indique ici d’afficher les enregistrements 10 par 10. Relancez l’ensemble :

RIAImage14

Nous avons donc bien la pagination en marche. Par contre, nous chargeons toujours l’ensemble des enregistrements malgré le fait de les visualiser par lot de 10. Il serait donc peut-être plus intéressant de charger les données au fur et à mesure que l’on avance dans la pagination. Pour cela, rien de plus simple ajoutez l’attribut suivant :

LoadSize="20"

à la source après l’attribut  AutoLoad="True" par exemple. Bah c’est tout ! Désormais, toutes les 2 pages, un lot de 20 enregistrements supplémentaires seront chargés en mémoire en asynchrone et en tâche de fond sans que vous n’ayez rien eu à faire.

Le contrôle ActivityControl

L’inconvénient de ces chargements asynchrones est que l’utilisateur ne comprends par forcément ce qu’il se passe lorsqu’il lance une action en cliquant et que cela met quelques millisecondes à s’afficher. Il faut donc le faire patienter et lui indiquer qu’une opération est en cours.

Pour cela, récupérez le fichier attaché à ce billet « ActivityControl.zip » contenant l’assembly « ActivityControl.dll ». Ajoutez ensuite une référence à cette assembly dans votre projet Silverlight. Ce contrôle sera probablement directement intégré dans la version finale de .NET RIA Services.

Ce contrôle est maintenant directement présents dans les références d’un projet de type Business Application. Il ne reste donc plus qu’à ajouter cet espace de nom à votre contrôle :

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

Puis englobez le StackPanel contenant la grille et le DataPager entre ces 2 balises XAML :

<activity:Activity IsActive="{Binding IsBusy, ElementName=source}" VerticalAlignment="Top" HorizontalAlignment="Left"></activity:Activity>

Désormais, grâce à cela, lorsque l’on arrive sur la 3ème page le chargement des 20 prochains enregistrements est fait pendant qu’une animation « Loading » se lance :

RIAImage15

Groupons les données

Si l’on souhaite grouper les enregistrements par pays par exemple, c’est à nouveau d’une simplicité déconcertante. En dessous du tri par « CompanyName » de notre DomainDataSource, ajoutez ce XAML :

<riaControls:DomainDataSource.GroupDescriptors
    <riaData:GroupDescriptor PropertyPath="Country" />
</
riaControls:DomainDataSource.GroupDescriptors>

Et voici le résultat :

RIAImage16

On peut même fermer les nœuds pour une meilleure visibilité (comme ici Austria).

Gestion de la sauvegarde

Ajoutons d’abord un bouton pour laisser l’utilisateur sauvegarder ses changements. Pour cela, insérer le bout de XAML dans le StackPanel au dessus de la grille :

<Button x:Name="BoutonSauvegarde" Content="Sauvegarder les changements" Click="BoutonSauvegarde_Click" />

Maintenant, il nous faut lancer l’opération de sauvegarde avec ce code C# :

private void BoutonSauvegarde_Click(object sender, System.Windows.RoutedEventArgs e)
{
    if (source.HasChanges) 
    {
        source.SubmitChanges(); 
   
    else 
   
        MessageBox.Show("Aucun changement detecté."); 
    }
}

Notre objet contenant les enregistrements en mémoire maintient en effet une liste des modifications effectuées (ajout, suppression ou modification). On teste donc le booléen HasChanges pour savoir si quelque chose a été changé par l’utilisateur et si c’est le cas on voit les changements au serveur Web via la commande SubmitChanges() pour que ce dernier s’occupe à son tour de mettre à jour la base de données.

Utilisation d’une Child Window

Si aucun changement n’a été détecté et que l’utilisateur clique sur le bouton de sauvegarde, une fenêtre externe à Silverlight de style popup JavaScript est levée :

RIAImage17


Ce n’est pas optimal en termes d’expérience utilisateur. On va utiliser une autre nouveauté de Silverlight 3 pour améliorer tout cela. Ajoutez un nouvel élément à votre projet Silverlight de type « Silverlight Child Window » et nommez le « InfoWindow.xaml » :

RIAImage18

Remplacez le XAML proposé par celui-ci :

<controls:ChildWindow x:Class="GestionClientsRIA.InfoWindow" 
           xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation 
           xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 
           Width="200" Height="100" 
           Title="Information utilisateur"> 
    <Grid x:Name="LayoutRoot" Margin="2"> 
        <Grid.RowDefinitions
            <RowDefinition /> 
            <RowDefinition Height="Auto" /> 
        </Grid.RowDefinitions
        <TextBlock x:Name="InfoToDisplay" Grid.Row="0" /> 
        <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
    </Grid>
</controls:ChildWindow>

Revenons maintenant dans notre vue HomePage.xaml.cs et utilisez ce code en remplacement du précédent :

private int nombreEntiteesModifiees = 0;

private void BoutonSauvegarde_Click(object sender, System.Windows.RoutedEventArgs e)

    if (source.HasChanges) 
   
        nombreEntiteesModifiees = source.DomainContext.Entities.GetChanges().ModifiedEntities.Count(); 
        source.SubmitChanges(); 
   
    else 
   
        InfoWindow infoWindow = new InfoWindow(); 
        infoWindow.InfoToDisplay.Text = "Aucun changement détecté."
        infoWindow.Show(); 
    }


private void source_SubmittedChanges(object sender, SubmittedChangesEventArgs e)

    InfoWindow infoWindow = new InfoWindow(); 
    infoWindow.InfoToDisplay.Text = nombreEntiteesModifiees + " modifications effectuées"
    infoWindow.Show(); 
    nombreEntiteesModifiees = 0;
}

Et ajoutez ce « using » :

using System.Windows.Ria.Data;

Enfin ajoutez l’abonnement à l’évènement SubmittedChanges au niveau de la source dans le XAML :

SubmittedChanges="source_SubmittedChanges"

On a désormais une expérience utilisateur plus « intégrée » :

RIAImage19

Et on a surtout la main sur le design de la fenêtre affichée. J’aurais pu y mettre de la vidéo, une belle image, etc.


Mise en place d’une règle de validation

Maintenant que nous laissons l’utilisateur sauvegarder les données, il serait peut-être bon d’ajouter un peu de validation de ses saisies. Retournons dans l’application ASP.NET et plus précisément dans le fichier « CustomersService.metadata.cs » qui fut généré automatiquement grâce à la case « Generate associated classes for metadata ».

Rendez-vous sur le champ Country (Pays). Nous allons spécifier une expression régulière sur ce champ indiquant que les valeurs autorisées ne peuvent qu’être des caractères alphabétiques commençant par une majuscule. Cela nous donne le résultat suivant :

[RegularExpression("[A-Z][A-Za-z]*", ErrorMessage="Les caractères non alphabétiques ne sont pas autorisés")]
public string Country;

On indique également le message d’erreur a affiché si l’utilisateur s’égard à vouloir insérer des caractères étranges pour saisir le nom du pays. Compilez l’ensemble et testez la solution.

RIAImage20


Si vous tentez alors de modifier un nom de pays en ajoutant un chiffre, le message d’erreur de validation est automatiquement levé. Aucun aller/retour serveur n’a été nécessaire pour cela, la logique est bien embarquée coté client Silverlight. Il suffit d’aller le voir dans le proxy client généré :

[DataMember()]
[RegularExpression("[A-Z][A-Za-z]*", ErrorMessage="Les caractères non alphabétiques ne sont pas autorisés")]
[StringLength(15)]
public string Country
{
    get
    {
        return this._country;
    }
    set
    {
        if ((this._country != value))
        {
            this.ValidateProperty("Country", value);
            this.OnCountryChanging(value);
            this.RaiseDataMemberChanging("Country");
            this._country = value;
            this.RaiseDataMemberChanged("Country");
            this.OnCountryChanged();
        }
    }
}

Un ensemble d’attributs peuvent ainsi être spécifiés sur les champs de vos objets métiers couvrant les scénarios les plus communs. Vous pouvez également implémenter votre propre logique de validation avec une classe de type « Shared » qui sera automatiquement répliquée coté client.

Concluons et observons le résultat final en action en vidéo dans le 4ème et dernier billet.

  • hihi tu vas trouver ça marrant : de google je tombe sur ton article page 3/4. Impossible d'aller à la page 1 ou 2. J'ai essayé de mettre 2-3 dans l'url au lieu de  3-4. Mais ne marche pas.

    Peux tu, stp, me donner le lien ? Merci, et encore une fois super tuto ! J'arrive pas à mettre le ActivityContrl mais j'ai pas encore passer trop de temps dessus.

    Super tuto !

  • Nan ba par chance, ils sont encore dans tes recent post loooool ! Quel naab ! :paf:

    Dsl ! ^^

  • Aujourd'hui j'ai éssayé de faire l'ensemble de ton tuto. je reste bloqué avec le datapager : lorsque le datasource doit recharger 20 enregistrements, rien ne se passe. Mais la page 1 et 2 fonctionne !

    Ensuite, est ce normal que je ne puisse pas sélectionner une ligne du datagrid ?

    Merci davrous !!

  • Hello nk54,

    Il faut avoir auparavant trier la source de données sinon Entity Framework ne supporte pas le tri. Tu devrais surement voir une erreur de levée sur le Skip puis Take dans les traces reseaux car tu n'as pas trié la source.

    C'est pour ça que dans mon post, j'ai d'abord trier par CompanyName avant d'appliquer le sorting.

    Bye,

    David

  • Bonjour,

    Actuellementy je suis en train de developper une appli avec silverlight 3.

    je suis confronté a 2 pb;

    1) j'arrive pas à creer des courbes avec le composant chartingToolkit:LineSeries dont les coordonnées sont chargés de la base de donnée grace au RIA, donc je dispose d'un objet de type ENtityList.

    quand je fais :

    courbe_de_conso = chart_conso.Series[0] as LineSeries;

    courbe_de_conso.ItemsSource=monContexte.Clients;

    où Client est un entitylist, apres dans le xaml je mets

            <chartingToolkit:LineSeries Title="Consommation"

                                                           ItemsSource="{Binding}"

                                        DependentValueBinding="{Binding NUM}"

                                        IndependentValueBinding="{Binding DAT}">

                               </chartingToolkit:LineSeries >

    ça marche pas!!!

    2) avec le meme  entitylist je veux afficher des données dans une datagrid sauf que je veux afficher que certaines colonnes d'une table et pas toutes comment faire???

    qqun aurait une idée svp

    merci!!

  • Bonjour et merci pour le tuto

    j'utilise des champs du type geography de SQL SERVEUR, comment faire pour que entity en tienne compte

  • Bonjour,

    Non les champs de type geography ne sont pas supportés pas Entity Framework. Entity Framework se cantonne à ce qui est commun à toutes les bases. Cela arrivera donc peut-être un jour avec LINQ2SQL (qui lui est spécifique à SQL Server).

    Bye,

    David

  • Bonjour,

    très intéressant ce tuto ainsi que ton coaching Silverlight 3 sur msdn.

    Je rencontre pour ma par un problème pour la partie RIA Services, impossible de trouver les tools à installer en français pou VS 2008 SP1

    Saurais-tu où je peux me procurer cela ?

  • Hello,

    Effectivement, la version de juillet pour SL3/VS2008 de .NET RIA Services n'existe que pour des versions EN-US. Il n'y aura jamais de mise à jour de .NET RIA Services pour cette version. Par contre, la version finale visant SL4/VS 2010 sera bien localisée en FR d'ici quelques jours. Si vous souhaitez en savoir davantage, j'ai fait d'autres tutoriaux ici : blogs.msdn.com/.../tutorial-silverlight-4-wcf-ria-services-avec-0-ligne-de-code.aspx

    Bye,

    David

Page 1 of 1 (9 items)
Leave a Comment
  • Please add 7 and 3 and type the answer here:
  • Post