Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Bonjour lecteur,

J’ai eu le plaisir d’animer deux sessions au techdays que vous pouvez retrouver ici :

RDA106 : WPF pour les développeurs Windows Forms

IND115 : Le cycle de vie des applications Web en détail

Au plaisir de lire vos remarques.

Musa.

0 commentaire(s)
Classé sous :

Nova_Reader_EN

Un petit post rapide pour répondre à une question que l’on me pose souvent concernant WPF. Peut-on, comme en DirectX, accéder à la boucle de rendu qui par défaut est masquée ?

Pour être claire on accède pas directement à la boucle de rendu, par contre il  existe une classe utile qui nous donne accès à chaque frame rendue:

CompositionTarget

Cette classe représente la surface sur laquelle WPF dessine et vous donne accès, via l’event ci-dessous, à chacune des frame dessinées.

CompositionTarget.Rendering += new System.EventHandler(CompositionTarget_Rendering);

Vous pouvez alors, à loisir, modifier la surface rendu (pour des animations custom notamment), le contenu du rendu (positionnement des éléments pour du billboarding par exemple).

Voilà la réponse publique est faite.

Musa

0 commentaire(s)
Classé sous :

Un petit post pour vous faire part d’un mini-tutoriel sur comment analyser les performances d’une application mobile Windows Mobile (basé sur Windows CE).

Vous trouverez, donc,  ci-dessous les outils disponibles pour l’analyse des performances sur une application .NET Compact Framework 2.0 SP1 ou supérieure (3.5 notamment).

Deux moyens sont disponibles pour la gestion des performances :

  • Génération automatique des statistiques (via un fichier avec l’extension .stat) ,
  • Utilisation de l’outil du .NET Compact Framework 2.0 : Remote Performance Monitor,
  • Un mode artisanal pour la mémoire,  à la main :)

Faisons tout d’abord un petit tour des applications remote existante pour accéder aux différentes ressources de votre Mobile :

Les outils de remote :

  • Remote registry Editor : Accès à la base de registre du mobile pour y effectuer des modifications,
  • Remote Process Viewer : Accès aux process en cours d’exécution,
  • Remote File viewer : Accès au file system du pocket,
  • Remote Performance monitor :  Exécution d’une application à distance et analyse des performances de cette dernière.

Tutoriel sur l’analyse des performances via un fichier (.stat):

  • Etape 1 : Copier les fichiers suivants ( accessible ici : C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\wce500\ )  dans le répertoire “\Windows” du mobile (Attention : Ces fichiers sont à destination d’un processeur donné ARM, SH etc…) :
    1. NetcfLaunch.exe,
    2. Netcfrtl.dll.
  • Etape 2 : Déverrouiller ou créer la clé suivante, avec la valeur 1, dans la base de registre du mobile HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETCompactFramework\PerfMonitor,
  • Etape 3 : Exécuter votre application,
  • Etape 4 : Un fichier (*.stat) est automatiquement généré. Ce dernier peut être importé dans Excel ou lu via le Remote Performance Monitor.

Tutoriel sur l’analyse des performances via le Remote Performance Tools :

  • Etape 1 : Sur mon poste de travail il se trouve ici : « C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\bin », le lancer,
  • Etape 2 : Copier les fichiers suivants ( accessible ici : C:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\wce500\ )  dans le répertoire “\Windows” du mobile (Attention : Ces fichiers sont à destination d’un processeur donné ARM, SH etc…) :
    1. NetcfLaunch.exe,
    2. Netcfrtl.dll.
  • Etape 3 : Exécuter le fichier NetcfLaunch.Exe,
  • Etape 4 : Choisissez «File\ Live counters » dans l’outil de perf,
  • Etape 5 : Il faut saisir ou choisir le mobile connecté (via ActiveSync ou, une adresse IP et un port, fourni en exécutant NetcfLaunch.exe),
  • Etape 6 : Saisissez l’application à analyser et les paramètres éventuelles puis cliquez sur « connect » en bas de l’écran comme ci-dessous:clip_image002

Les informations de performance apparaissent sur l’écran.

Artisanat :

Analyse de la mémoire dans le code : GC.GetTotalMemory() est votre ami pour analyser la mémoire managée utilisée par votre application.

Pour aller plus loin :

http://msdn2.microsoft.com/en-us/library/ms172524.aspx : Performance et diagnostic avec les Pocket PC

http://msdn2.microsoft.com/en-us/library/ms404355(VS.80).aspx : Utilisation du Remote Performance Monitor

http://blogs.msdn.com/davidklinems/archive/2005/12/09/502125.aspx : Détail les compteurs de performance accessible par les outils précédent.

N’hésitez pas à me faire part de vos remarques :o)

Musa.

Lorsque l'on souhaite développer une application de gestion, l'une des premières tâches effectuées est la liaison de données entre une collection(d'objet métier) et des contrôles visuelles: une liste déroulante, une liste de données. Il est alors possible de faire des modifications de données à deux niveaux : Soit via le contrôle visuelle, soit via la stucture de données liée directement.

Une chose intéressante dans le DataBinding c'est sa bidirectionnalité à savoir que si nous modifions les données liées au contrôle par son intermédiaire, la structure de données sous-jacente est modifiée et inversemement.

Nous regarderons donc comment faire en sorte que, lorsque l'on modifie nos données métier, les contrôles sont automatiquement mis à jour.

Ce post fait suite à un précédent concernant le Databinding en WPF que vous trouerez ici

Première étape: notre application WPF

image 

Notre application affiche des personnes qui ont été ajoutées dans une collection elle même liée à une listbox.

Deux boutons permettent d'interagir avec la liste:

  • Insert : Ajoute une nouvelle personne dans la liste,
  • Modification : Modifie le premier élément de la liste en changeant le texte "Myamoto" en "Samouraï Musashi".

Seconde étape: la strucutre de données

Pour réaliser notre application nous allons nous appuyer sur deux classes :

  • Personne : correspondant à une personne,
  • PersonneCollection : Correspondant à une collection de personne (collection typée donc).

La classe personne est comme suit :

public class Person : { private string surname; public string Surname { get { return surname; } set { surname = value; } } private string name; public string Name { get { return name; } set { name = value; } } private string adress; public string Adress { get { return adress; } set { adress = value; } } public Person() { } }

La classe PersonneCollection est comme suit :

public class PersonCollection : Collection<Person> { }

Troisième étape : le code de la fenêtre

<Window x:Class="WpfApplicationDataBindingPart2.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplicationDataBindingPart2" Title="Liste de personnes" Height="300" Width="300" Loaded="Window_Loaded"> <Window.Resources> <local:PersonCollection x:Key="Persons"> <local:Person Name="Myamoto" Surname="Musashi" Adress="Bewise" /> <local:Person Name="Delta" Surname="Kosh" Adress="Bewise" /> <local:Person Name="Lolo" Surname="Suchii" Adress="Bewise" /> </local:PersonCollection> <DataTemplate x:Key="dtPerson"> <StackPanel> <TextBlock Text="{Binding Path=Name}" FontSize="14" FontWeight="Bold" /> <TextBlock Text="{Binding Path=Surname}" /> <TextBlock Text="{Binding Path=Adress}" /> </StackPanel> </DataTemplate> <Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}"> <Setter Property="Margin" Value="2" /> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="75*" /> <RowDefinition Height="25*" /> </Grid.RowDefinitions> <Border BorderBrush="DarkGoldenrod" BorderThickness="3" Grid.Row="0"> <ListBox x:Name="lstPerson" ItemsSource="{Binding}" DataContext="{StaticResource Persons}" ItemTemplate="{StaticResource dtPerson}" ItemContainerStyle="{StaticResource ListBoxItemStyle}"/> </Border> <StackPanel Grid.Row="1"> <Button x:Name="btInsert" Content="Insert" Width="120" Height="20" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2" Click="btInsert_Click"/> <Button x:Name="btModify" Content="Modification" Width="120" Height="20" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="2" Click="btModify_Click"/> </StackPanel> </Grid> </Window>

Je ne rentre pas trop dans le détail voici un focus sur les points importants :

  • L'instanciation de la collection personne faite de cette façon :

<local:PersonCollection x:Key="Persons"> <local:Person Name="Myamoto" Surname="Musashi" Adress="Bewise" /> <local:Person Name="Delta" Surname="Kosh" Adress="Bewise" /> <local:Person Name="Lolo" Surname="Suchii" Adress="Bewise" /> </local:PersonCollection>

  • Le Binding dans la listbox :

<ListBox x:Name="lstPerson" ItemsSource="{Binding}" DataContext="{StaticResource Persons}" ItemTemplate="{StaticResource dtPerson}" ItemContainerStyle="{StaticResource ListBoxItemStyle}"/>

Notre souci est donc comment faire réagir le contrôle listbox dés lors que l'on  :

  • Ajoute un élément dans la ListBox,
  • Modifie les propriétés d'une personne de la liste en question.

Quatrième étape : Faire réagir le contrôle à l'ajout d'un élément de notre liste

Pour notifier et rafraichir notre contrôle lors de l'ajout d'un élément dans notre liste, il faut que notre collection personnalisée hérite d'une interface nommée INotifyCollectionChanged. Cette interface va nous permettre d'implémenter un évènement que l'on déclenchera lors de l'ajout et la suppression d'élément dans notre liste. Le code de notre collection devient donc :

public class PersonCollection : Collection<Person>, INotifyCollectionChanged { public void Add(Person item) { base.Add(item); ExecuteCollectionChanged(NotifyCollectionChangedAction.Add, item); } public void Remove(Person item) { base.Remove(item); ExecuteCollectionChanged(NotifyCollectionChangedAction.Remove, item); } void ExecuteCollectionChanged(NotifyCollectionChangedAction action, Person item) { if (CollectionChanged != null) { CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item)); } } #region INotifyCollectionChanged Members public event NotifyCollectionChangedEventHandler CollectionChanged; #endregion }

Une fois cette interface implémentée sur notre liste, L'interface réagit lors du click sur insert et le nouvel élément s'affiche à l'écran. le code du bouton insert est le suivant :

private void btInsert_Click(object sender, RoutedEventArgs e) { PersonCollection people = this.Resources["Persons"] as PersonCollection; people.Add(new Person { Name = "Mim", Surname = "Mimetis", Adress = "Bewise" }); }

Le résultat de l'affichage après l'ajout de MIM dans la liste :

image

Cinquième étape : Faire réagir le contrôle à la modification d'une propriété d'un élément de la liste

De la même manière, nous souhaitons faire réagir notre contrôle dés que nous modifions une propriété d'une personne de la liste. Pour cela, comme pour notre collection, nous devons utiliser une  interface implémentée par notre classe Personne. Elle se nomme : INotifyPropertyChanged. une fois implémenté, notre classe personne est la suivante :

public class Person : INotifyPropertyChanged { private string surname; public string Surname { get { return surname; } set { if (value != surname) { surname = value; NotifyPropertyChanged("Surname"); } } } private string name; public string Name { get { return name; } set { if (value != name) { name = value; NotifyPropertyChanged("Name"); } } } private string adress; public string Adress { get { return adress; } set { if (value != adress) { adress = value; NotifyPropertyChanged("Adress"); } } } public Person() { } private void NotifyPropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }

Nous déclenchons donc l'évènement de notification de changement à chaque fois qu'une propriété est modifiée. Le code suivant du bouton "Modification" est donc désormais fonctionnel et chaque changement met à jour la listbox.

Le code du bouton Modification est le suivant :

private void btModify_Click(object sender, RoutedEventArgs e) { PersonCollection people = this.Resources["Persons"] as PersonCollection; Person musashi = people[0] as Person; musashi.Name = "Samouraï Musashi"; }

Le résultat de la modification est là :

image 

Sixième étape : remarque sur les collections

Nous avons, pour bien comprendre le mécanisme de notification, utiliser une collection personnalisée pour réaliser le DataBinding. Il faut savoir que WPF met à notre disposition une collection générique qui hérite déjà de INotifyCollectionChanged c'est l' ObservableCollection<T>. Celle - ci nous permet donc de nous passer de PersonnCollection. Elle se déclare de la façon suivante

ObservableCollection<Person> people;

Dans le prochain Post sur le DataBinding nous analyserons les BindingExpression et regarderons sur un cas concret comment mettre en oeuvre le DataBinding de manière efficace et performante

Musa.

0 commentaire(s)
Classé sous :

La BDC 2008 terminé, vous pouvez désormais retrouver tous les WebCasts des sessions en ligne à cette adresse : Les WebCasts 

La session plénière avec 1h15 de Silverlight 2, DeepZoom, WCF, ASP.NET Dynamic Data et autres LINQ, un bonheur pour le speaker, un bonheur pour les spécateurs à revivre ci-dessous:

Part 1 : http://www.bewise.fr/fr-FR/technos/Pages/DetailWebcast.aspx?ID=25

Part 2 : http://www.bewise.fr/fr-FR/technos/Pages/DetailWebcast.aspx?ID=26

Part 3 : http://www.bewise.fr/fr-FR/technos/Pages/DetailWebcast.aspx?ID=27

Part 4 : http://www.bewise.fr/fr-FR/technos/Pages/DetailWebcast.aspx?ID=28

Sinon feriez-vous confiance à cette bande de geek la ?

60 

pour vous donner un ordre d' idée, la session plénière ça donnait ça  :

BEWISE-pleniaire

Retrouvez d'autres ressources et articles ici : http://www.bewise.fr/fr-FR/technos/Pages/Articles.aspx

Retrouvez d'autres WebCast ici : http://www.bewise.fr/fr-FR/technos/Pages/Webcasts.aspx

Bon visionnage.

Musashi.

0 commentaire(s)
Classé sous : ,

Un des effets sympa que l'on utilise très courament c'est le rollover sur un bouton. En quoi cela consiste pour le néophyte ? C'est simplement le fait d'appliquer une modification visuelle sur un objet dés que la souris passe dessus. Alors comme ça c'est simple mais en Silverlight les choses se complique un peu et je m'en vais vous expliquer comment ajouter cet effet. L'avantage c'est que cela nous permettra de faire le tour de quelques notions sympa en Silverlight comme les styles et les templates. Alors prenons l'exemple d'nu bouton "insert"

Lorsque le bouton est dans son état normal il a ce rendu là : 

image

Une foi la souris passé dessus voilà le rendu :

image

Bien sur rien de magique la dedans j'ai juste utilisé deux images différentes. Il est à noter qu'un bouton Silverlight à d'origine cette tête là :

image

Je remercie mitch pour le design comme d'hab un développeur WPF et Silverlight n'est rien sans le meilleur designer :o)

 

Création d'un bouton avec deux images:

La création d'un bouton en Xaml est réalisé par la classe "Button"

<Button Width="140" Height="30" x:Name="insertButton" Click="insertButton_Click" />

Pour bien comprendre notre bouton, une petite explication s'impose , définissons ce que sont les Styles et les Templates.

Les styles

Ils correspondent au style css, ils permettent de spécifier des valeurs à des propriétés pour un type donné. ils sont basés sur la classe Style. Par exemple si je veux créer des boutons qui sont toujours espacés de 3 pixels il suffit de créer le style suivant :

<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Margin" Value="3" /> </Style>

Puis pour qu'ils soient appliqués à un bouton, il faut affecter la propriété Style de ce dernier à notre "ButtonStyle":

<Button Width="140" Height="30" x:Name="insertButton" Style="{StaticResource ButtonStyle}" Click="insertButton_Click" />

Les Templates

Les templates correspondent au rendu du bouton. Par exemple si je veux que mon bouton soit elliptique au lieu de carré, si je veux qu'il comporte une image au lieu de son rendu actuel c'est le rôle du Template.

Dans notre cas, nous allons nous attarder sur le contrôle Template et redéfinir complètement le layout de notre bouton.

Les styles et les templates peuvent se méler car le ControlTemplate est une propriété des contrôles silverlight. On peut donc créer un style qui modifie le ControlTemplate. Ce sera notre cas.

Nous réalisons cela comme suit :

<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Margin" Value="3" /> <Setter Property="ControlTemplate"> <Setter.Value> <ControlTemplate> <!-- Nous mettons ici le rendu de notre Control--> </ControlTemplate> </Setter.Value> </Setter> </Style>

Le Template de notre Boutton contient donc deux images qui se superspose. Seule l'une des deux images s'affiche suivant l'état de notre contrôle. Pour cela nous jouons sur l'opacité des images. Dans notre cas, l'opacité de l'image normale est de 1 et celle de l'image s'affichant lors du rollover est de 0.

<Style TargetType="Button" x:Key="ButtonStyle"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid x:Name="RootElement"> <Image x:Name="ImgInsert" Source="/Images/IcoInsert.png" Opacity="1"/> <Image x:Name="ImgInsertRO" Source="/Images/IcoInsertRO.png" Opacity="0"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

L'animation

Une fois notre contrôle créé, il nous reste à créer l'animation et appliquer notre style au contrôle. L'animation modifiera l'opacité des boutons pour les passer de 1 à 0 et inversement. Le déclencheur sera l'évènement MouseOver.

<Style TargetType="Button" x:Key="ButtonStyle"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid x:Name="RootElement"> <Image x:Name="ImgInsert" Source="/Images/IcoInsert.png" Opacity="1"/> <Image x:Name="ImgInsertRO" Source="/Images/IcoInsertRO.png" Opacity="0"/> <Grid.Resources> <Storyboard x:Key="Normal State" /> <Storyboard x:Name="StoryButton" x:Key="MouseOver State"> <DoubleAnimation Storyboard.TargetName="ImgInsert" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.1"/> <DoubleAnimation Storyboard.TargetName="ImgInsertRO" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.1"/> </Storyboard> </Grid.Resources> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

Nous appliquons enfin ce style à notre contrôle comme vue précédement et le tour est joué.

Hope to help you !

Musashi.

0 commentaire(s)
Classé sous :

Je ne le ferais pas souvent mais fort est de constater que là, j'ai été très impressionné par le travail réalisé par mon Jedi Master donc je vous transmet l'info.  Un moteur 3D entièrement en Silverlight. la démonstration est impressionante !!

Son blog est ici et la démonstration du moteur 3D est là http://www.vertice.fr/NovaLight/NovaLightTestPage.html

Quelques photos pour donner envie (je confirme qu'il n'est pas Designer :o) ) :

image

et ça :

image

 

Musashi. 

5 commentaire(s)
Classé sous :

La BDC c'est des sessions, des nouveautés, un jeux concours avec une TV LCD de 94 cm à gagner  .... mais surtout plein de SQL Server 2008, SharePoint, ASP.NET, Team System et beaucoup, beaucoup de Silverlight 2

Le détail du contenu de l'évènement le plus attendu de Toulouse

Les inscriptions sont par là !

En attendant, une petite vidéo des coulisses de la préparation...

 

Retrouver Jean-Pierre sur son blog technique dédié à SQL Server et ASP.NET ici

A bientôt,

Musashi.

 

3 commentaire(s)
Classé sous :

Vous l'avez surement appris, Silverlight 2.0 vient de sortir suite à l'annonce du MIX 2008. Vous pouvez télécharger tout ce qui vous est nécessaire au développement d'une application Silverlight 2.0 à ces différents liens:

Je ne parlerais pas de Blend dans ce post (c'est un outil pour graphiste ça ! pas pour développeur :o) )

Nous allons donc voir :

  • Une vue d'ensemble de Silverlight 2.0 avec VS 2008,
  • Le hosting en deux mots (vraiment deux mots),
  • développement d'une première application.

Vue d'ensemle de Silverlight avec Visual Studio 2008

Donc voici comment se présente Silverlight 2.0 lorsque l'on souhaite créer un nouveau projet dans Visual Studio 2008:

image

Deux possibilités s'offre à vous, soit créer une Application Silverlight , soit créer une Dll Silverlight. Ce sont les mêmes type de projet qui étaient à votre disposition avec la version 1.1 Alpha (mais oublions la voyons !!!!).

Lorsque vous créez une application, un assistant démarre vous proposant :

image

Comme beaucoup le savent silverlight est un plugin. Il doit donc être hébergé par une application Web (HTML ou ASP.NET) .

Ainsi cette écran vous propose soit de créer un projet Silverlight et son hôte Web en même temps (avec la possibilité de choisir Web Site ou Web application project) , soit de créer uniquement le projet Silverlight à héberger soit même à la main (c'est le cas ou vous avez déjà un site Web qui l'hébergera par exemple).

Dans le premier cas vous obtiendrez cela :

image

Donc un site Web et l'application Silverlight.

Dans le second , seulement le projet Silverlight :

image

Bon bref, voilà trois impression d'écran qui n'impressionne pas et que vous retrouverez dans tous les tutoriels mais ma joie m'obligeait de vous les présenter !

Première chose qui frappe dans le projet Silverlight , sa ressemblance avec un projet WPF !

Le hosting de Silverlight au sein de votre application ASP.NET

Mais quoi de neuf au niveau du hosting ? Ceux qui comme moi ont développé avec la version 1.0 (celle qui nous obligeait à nous torturer le Javascript) seront heureux d'apprendre que des contrôles ASP.NET existe pour héberger Silverlight dans votre DIV. Voici l'exemple que j'ai utilisé (fournit par MS):

<asp:Silverlight BorderWidth="2" BorderColor="AliceBlue" ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication1.xap" Version="2.0" Width="100%" Height="100%" BackColor="Black" />

 

L'application Silverlight quand à elle, présente deux fichiers

  • App.xaml : qui correspond à une instance d'Application en fait
  • Page.xaml : qui correspond  au contenu exposé par le plugin.

Mais passons aux choses sérieuses, faisons, ce que tous le monde attends : du Windows dans du Web via l'utilisation de contrôles utilisateurs RICHE !

Les contrôles et la construction d'une page

Ce n'est plus un Canvas qui nous accueil mais un UserControl qui constitue le body de notre page

<UserControl x:Class="SilverlightApplication1.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SilverlightApplication1" Loaded="UserControl_Loaded" Width="1024" Height="780"> </UserControl

Ensuite , on se fait plaisir en ouvrant la toolbox (et on craint de ne voir que des canvas et autre ellipse ...) Mais non c'est la magnifique fenêtre suivante qui nous ouvre grand les bras:

image

Donc, non seulement la fenêtre est pleine de contrôles, mais surtout l'essentiel est là pour démarrer une application riche ce que nous allons faire !

Allez je vous propose de partir sur un truc simple, un player Vidéo :o) ah non ça c'était le seul truc que l'on pouvais montrer avec la version 1.0 ..... Donc plutôt une modeste application avec trois zones de saisie et un bouton. Cette dernière instanciera un User (Nom prénom et age) et  nous affichera son contenu dans les zones. voilà donc le résultat que nous attendons.

image

Tout d'abord nous créons une Classe User utltra simple :

using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace SilverlightApplication2 { public class User { public string Nom { get; set; } public string Prenom { get; set; } public int Age { get; set; } } }

puis, nous créons l'interface utilisateur : Pour cela nous avons besoin de trois zones de saisies, un bouton, et un textblock

<Grid x:Name="LayoutRoot" Background="White"> <StackPanel > <TextBox x:Name="txtNom" Margin="3" BorderThickness="2" BorderBrush="DarkViolet"/> <TextBox x:Name="txtPrenom" Margin="3" BorderThickness="2" BorderBrush="DarkViolet"/> <TextBox x:Name="txtAge"Margin="3" BorderThickness="2" BorderBrush="DarkViolet"/> <Button Content="Save" Width="150" Height="30" HorizontalAlignment="Left" Margin="3" Click="Button_Click"/> <TextBlock x:Name="txtResultat" /> </StackPanel> </Grid>

Première chose qui nous apparait :

  • Nous avons des contrôles de Layout (StackPanel, Grid, Canvas) ce qui nous facilite grandement le positionnement des objets dans nos surfaces.
  • Puis nous réalisons un positionnement relatif à l'aide de la propriété Margin

Regardons désomais le binding et notamment comment instancier un objet en XAML. Pour cela plusieurs étapes :

  • 1 - référencer votre namespace, nommé local dans notre contexte:
<UserControl x:Class="SilverlightApplication2.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SilverlightApplication2" Width="400" Height="300">
  • 2 - Créer votre resource qui instancie votre user
<UserControl.Resources> <local:User x:Key="my" Nom="Musashi" Prenom="Myamoto" Age="32" /> </UserControl.Resources>
  • 3 - Réaliser le dataBinding
    • Ajouter votre user "my" au dataContext( l'équivalent d'une DataSource) de votre StackPanel
    • Ajouter le binding sur chacune des zones de saisie

<StackPanel DataContext="{StaticResource my}"> <TextBox x:Name="txtNom" Text="{Binding Nom}" Margin="3" BorderThickness="2"/> <TextBox x:Name="txtPrenom" Text="{Binding Prenom}" Margin="3" BorderThickness="2"/> <TextBox x:Name="txtAge" Text="{Binding Age}" Margin="3" BorderThickness="2"/> <Button Content="Save" Width="150" Height="30" HorizontalAlignment="Left" Margin="3" Click="Button_Click"/> <TextBlock x:Name="txtResultat" /> </StackPanel>

Enfin la gestion des évènements, lorsque je clique sur le bouton, j'affiche un message dans le textBlock:

  • 1  - Evènement levé lors du click sur le bouton : "Button_Click"

<Button Content="Save" Width="150" Height="30" HorizontalAlignment="Left" Margin="3" Click="Button_Click"/>
  • 2 - Réaction à l'évènement

private void Button_Click(object sender, RoutedEventArgs e) { txtResultat.Text = "Save successfull"; }

Une fois réalisé cela, on relit son code et l'on se dit : il est un peu répétitif  le code de mes textBox et surtout elles ont toutes le même Style, donc vous finaliserez votre sample avec l'ajout d'un style qui permet automatiquement de postionner les bordures et le margin de l'ensemble de nos zones de saisies.

<Style TargetType="TextBox" x:Key="myTextBoxStyle"> <Setter Property="Margin" Value="3" /> <Setter Property="BorderThickness" Value="2"/> <Setter Property="BorderBrush" Value="DarkViolet"/> </Style>

Modification et code de l'ensemble de la fenêtre pour intégrer le style mis en ressource:

<UserControl x:Class="SilverlightApplication2.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SilverlightApplication2" Width="400" Height="300"> <UserControl.Resources> <local:User x:Key="my" Nom="Musashi" Prenom="Myamoto" Age="32" /> <Style TargetType="TextBox" x:Key="myTextBoxStyle"> <Setter Property="Margin" Value="3" /> <Setter Property="BorderThickness" Value="2"/> <Setter Property="BorderBrush" Value="DarkViolet"/> </Style> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel DataContext="{StaticResource my}"> <TextBox x:Name="txtNom" Text="{Binding Nom}" Style="{StaticResource myTextBoxStyle}"/> <TextBox x:Name="txtPrenom" Text="{Binding Prenom}" Style="{StaticResource myTextBoxStyle}"/> <TextBox x:Name="txtAge" Text="{Binding Age}" Style="{StaticResource myTextBoxStyle}"/> <Button Content="Save" Width="150" Height="30" HorizontalAlignment="Left" Margin="3" Click="Button_Click"/> <TextBlock x:Name="txtResultat" /> </StackPanel> </Grid> </UserControl>

Et là seulement tout est terminé !

Bon eh bien, je sais pas pour vous,  mais moi après ça j'ai eu un trop plein d'émotion et j'ai appelé tous mes collègues.

 

En conclusion : mon premier sentiment

Silverlight 2.0 est relativement stable, son utilisation est vraiment très très proche de celle de WPF ce qui permet de capitaliser sur ses acquis (et ça je dis un grand bravo !).

Bien sur , il manque des choses et l'on rencontre des problèmes (un intellisense capricieux, des erreurs ,dans les resources notamment)  mais mon premier sentiment après 3h d'utilisation et une bonne stabilité et un fonctionnel (contrôles, binding, template, style ...) présent et opérationnel.

Allez je vous fait bientôt un autre Post sur le développement d'une petite application de gestion qui met en jeu des choses plus avancées notamment au niveau du Databinding...

Musashi.

0 commentaire(s)
Classé sous :

Je souhaitais vous faire profiter d'une petite méthode utilitaire que j'ai réalisé cette semaine pour me faciliter la vie dans mes projets.

Si comme moi vous utilisez LINQ régulièrement et que vous l'utilisez dans le cadre de projet WPF, vous aimeriez bien pouvoir transformer le produit d'une requête LINQ en une ObservableCollection, et cela, afin de faciliter le databinding (bidirectionnelle).

Ainsi, si on observe la variable users crée comme suit :

var users = from u in UserManager.GetUsers()

where u.Age >= 18

select u;

Nous aimerions bien la lier avec une ListBox à l'aide d'une ObservableCollection comme suit :

lstUser.DataContext = users.ToObservableCollection<User>();

Techniquement, il s'agit donc de transformer une collection IEnumerable<T> (résultat de la requête LINQ) en ObservableCollection <T> pour cela, je vous propose une méthode d'extension dont le code source est le suivant :

public static class ObservableCollectionTools

{

public static ObservableCollection<TSource> ToObservableCollection<TSource>(this IEnumerable<TSource> source)

{

ObservableCollection<TSource> target = new ObservableCollection<TSource>();

using (IEnumerator<TSource> enumerator = source.GetEnumerator())

{

while (enumerator.MoveNext())

{

target.Add(enumerator.Current);

}

}

return target;

}

}

Cela facilite donc notre travail nous permettant de réaliser facilement le Databinding entre une ListBox et le résultat d'une requête LINQ.

Une fois la méthode précédente insérée dans vos projets, l'utilisation est simple comme le montre le print screen suivant :

 

Solution complète

Afin de vous présenter une mise en œuvre complète, voici un exemple, qui affiche des users à partir d'une requête LINQ, en utilisant notre méthode d'extension :

Tout d'abord le code de la fenêtre WPF qui comporte la ListBox et un DataTemplate permettant d'afficher des users (Nom, prénom, âge)

< Window x : Class ="WpfExtensionObservableCollection.Window1"

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

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

xmlns:local="clr-namespace:WpfExtensionObservableCollection"

Title="Window1" Height="391" Width="510"

Loaded="Window_Loaded">

< Window.Resources >

< DataTemplate x : Key ="dtUser" DataType ="{ x : Type local : User }">

< StackPanel Orientation ="Vertical">

< TextBlock Text ="{ Binding Path =Name}" />

< TextBlock Text ="{ Binding Path =Surname}" />

< TextBlock Text ="{ Binding Path =Age}" />

</ StackPanel >

</ DataTemplate >

</ Window.Resources >

< Grid >

< StackPanel Grid.Column ="0" Orientation ="Vertical">

< ListBox x : Name ="lstUser" ItemsSource ="{ Binding }" ItemTemplate ="{ StaticResource dtUser }" Background ="Black" Foreground ="White"></ ListBox >

</ StackPanel >

</ Grid >

</ Window >

 

Il nous faut, de plus, une classe métier « User » et son manager « UserManager » pour nous exposer tous les users disponibles.

 

public class User

{

public string Name { get; set; }

public string Surname { get; set; }

public int Age { get; set; }

 

public User(string name, string surname, int age)

{

this.Age = age;

this.Name = name;

this.Surname = surname;

}

}

 

public class UserManager

{

public static List<User> GetUsers()

{

List<User> liste = new List<User>();

liste.Add(new User("Patrice", "test", 23));

liste.Add(new User("Jean-pierre", "test", 28));

liste.Add(new User("Sébastien", "test", 30));

liste.Add(new User("lolo", "test", 23));

liste.Add(new User("yann", "test", 24));

liste.Add(new User("Sacha", "test", 56));

liste.Add(new User("fred", "test", 34));

liste.Add(new User("Olivier", "test", 34));

liste.Add(new User("fabien", "test", 20));

liste.Add(new User("Julien", "test", 25));

liste.Add(new User("Alain", "test", 34));

liste.Add(new User("Alex", "test", 30));

return liste;

}

}

 

 

Puis le code behind de la fenêtre Windows qui utilise la requête LINQ pour filtrer les users (ceux de moins de 32 ans) à afficher en utilisant notre méthode d'extension.

 

public partial class Window1 : Window

{

public Window1()

{

InitializeComponent();

}

 

private void Window_Loaded(object sender, RoutedEventArgs e)

{

var users = from u in UserManager.GetUsers()

where u.Age < 32

select u;

 

lstUser.DataContext = users.ToObservableCollection<User>();

}

}

 

Le résultat, à l'exécution :

 

Hope to help you…

 

Musashi.

3 commentaire(s)
Classé sous : ,

Pour ce premier opus, d' une série ou nous étudierons le Databinding en WPF, j'ai choisi de présenter les différents moyens d' instancier et d' utiliser ses classes (du domaine par exemple) en XAML.

Nous verrons dans ce post les éléments suivants :

  • La création d' objet en XAML à partir de classe C#
  • L'objectDataProvider
    • Son utilisation,
    • Ses contextes d 'utilisations.

La classe de base que nous allons utiliser pour instancier nos objets en XAML est la classe "Contact" qui est représentée par la définition suivante:

public class Contact { public string Name { get; set; } public string Surname { get; set; } public Contact() { this.Name = "Test"; this.Surname = "Test"; } public Contact(string Name, string Surname) { this.Name = Name; this.Surname = Surname; } }

Comme vous pouvez le constater cette classe, simple,  possède deux membres (le prénom et le nom) ainsi que deux constructeurs l' un qui par défaut instancie l' objet avec des valeurs de test et l' autre qui prends deux paramètres correspondant aux deux membres.

Notre but est d' afficher une instance de la classe contact dans une fenêtre contenant deux zones de texte qui affiche ses membres comme montré ci-dessous

image

c'est la grande classe cette fenêtre, une vrai fenêtre de développeur non :o)

 

Le code source de cette fenêtre est le suivant :

<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="30*" /> <ColumnDefinition Width="70*" /> </Grid.ColumnDefinitions> <Grid Grid.Column="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="30*" /> <ColumnDefinition Width="70*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="25*" /> <RowDefinition Height="25*" /> </Grid.RowDefinitions> <TextBlock Text="Name : " Grid.Column="0" Grid.Row="0" /> <TextBlock x:Name="txtName" Text="{Binding Source={StaticResource TotoObject}, Path=Name}" Grid.Column="1" Grid.Row="0" /> <TextBlock Text="Surname : " Grid.Column="0" Grid.Row="1"/> <TextBlock x:Name="txtSurname" Text="{Binding Source={StaticResource TotoObject}, Path=Surname}" Grid.Column="1" Grid.Row="1" /> </Grid> </Grid>

Vous noterez qu' il existe une expression de Binding au niveau des textBlocks que j' expliquerais dans un prochain Post sinon ce code n' a rien de complexe.

Des grilles pour créer un layout et des zones de texte pour afficher les informations relatives à notre instance.

maintenant entrons dans le vif su sujet: la création d' objets pour afficher des informations !

Instanciation des objets du domaine en XAML

En se basant sur la classe "Contact" présentée précédemment  :

  • Référencer l'assembly contenant la classe Contact (wpfDataBinding_Part1 dans notre cas) dans votre fichier Xaml,

xmlns:local="clr-namespace:WpfDatabinding_Part1"

  • Créer une ressource correpondant à cette classe (et donc l' instancier) et affecter les valeurs des membres de notre objet afin de les afficher dans les textBlocks.,

<Window.Resources> <local:Contact x:Key="TotoObject" Name="Toto" Surname="Tata" /> </Window.Resources>

  • Nous pouvons aussi utiliser cette syntaxe pour arriver au même but
<local:Contact x:Key="TotoObject"> <local:Contact.Name>Test</local:Contact.Name> <local:Contact.Surname>Blablaa</local:Contact.Surname> </local:Contact>

C'est ainsi qu' un objet C# peut être créé en XAML. La façon de lier cet objet a la zone de texte passe par la création d' une liaison de données (Databinding)

<TextBlock x:Name="txtName" Text="{Binding Source={StaticResource TotoObject}, Path=Name}" Grid.Column="1" Grid.Row="0" />

La source du Binding est une ressource (au niveau de la fenêtre) c'est la raison pour laquelle elle est référencée à l' aide d' une expression "StaticResource".

Gestion des listes d' objets 

je souhaiterais créer en XAML une liste de contact via ma classe Contacts qui hérite de List<Contact> comme présenté ci-dessous:

public class Contacts : List<Contact> { }

Pour ce faire vous devez écrire le code suivant:

<local:Contacts x:Key="ListTest"> <local:Contact Name="Musa1" Surname="Bewise" /> <local:Contact Name="Musa2" Surname="Bewise" /> </local:Contacts>

L'objectDataProvider:

La deuxième façon de créer un objet en XAML correspond à utiliser un fournisseur de données comme l'objectDataProvider.

L'objectDataProvider est une abstraction des données réel pour en créer une donnée "Bindable". Ainsi à partir d'une source, un objet ou encore une méthode, il crée un instance suivant ce qui est retournée par l' objet ou la méthode. la liste suivante résume ces possibilités:

  • Créer un objet à partir de son instance en XAML,
  • Créer un objet à l' aide d' un constructeur paramétré,
  • Créer un objet à l' aide d' une méthode qui retourne une instance ou une collection.

 

Utilisation de l'objectDataProvider pour instancier un objet

Ci-dessous on crée un objet en local et l' on spécifie un objectDataProvider à partir de cet objet .

<Window.Resources> <local:Contact x:Key="bobObject" Name="Hiro" Surname="Nakamura" /> <ObjectDataProvider x:Key="TotoObject" ObjectInstance="{StaticResource bobObject}" /> </Window.Resources>

Cela ne vous a pas échapper précédemment, j' en suis sur :) , mais l' instance d' un objet créé directement en XAML s' appuie sur son constructeur par défaut (sans paramètre). Pour créer un objet à partir d' un constructeur spécifique on peut s' appuyer sur l'objectDataProvider comme ci-dessous:

<Window.Resources> <ObjectDataProvider x:Key="TotoObject" ObjectType="{x:Type local:Contact}"> <ObjectDataProvider.ConstructorParameters> <sys:String>Hiro</sys:String> <sys:String>Nakamura</sys:String> </ObjectDataProvider.ConstructorParameters> </ObjectDataProvider> </Window.Resources>

Une autre possibilité, instancier un objet à partir d' une méthode statique (utile dans le cas d' une Factory) :

<ObjectDataProvider x:Key="TotoObject" ObjectType="{x:Type local:ContactManager}" MethodName="GetContactInstance"> <ObjectDataProvider.MethodParameters> <sys:String>Hiro</sys:String> <sys:String>Nakamura</sys:String> </ObjectDataProvider.MethodParameters> </ObjectDataProvider>

Le code de ContactManager est le suivant :

public class ContactManager { public static Contact GetContactInstance() { return null; } public static Contact GetContactInstance(string Name, string Surname) { return new Contact(Name,Surname); } public static List<String> GetContactList() { List<String> liste = new List<string>(); liste.Add("Yann"); liste.Add("Fred"); liste.Add("David"); liste.Add("Sacha"); return liste ; } }

Dans l' exemple ci-dessus, nous pouvons noter 2 éléments importants :

  • La classe utiliser par l'objectDataProvider est ContactManager sur laquelle nous appelons la méthode "GetContactInstance" qui est statique,
  • L' objet instancier et contenu par l'objectDataProvider, est une instance de Contact (Celle retournée par notre méthode).

Utilisation de l'objectDataProvider pour instancier une liste de contact

Souvent nos composants visuelles utilisent des Listes et nous voudrions alors que notre ObjectDataProvider contiennent une liste d' objet pour l' afficher dans une ListBox comme ci-dessous

image

De la même manière que pour une instance d' objet, une liste d' objet peut être la source d' un ObjectDataProvider, comme montré ci-dessous, notamment en s' appuyant sur la méthode GetContactList de la classe ContactManager

<Window.Resources> <ObjectDataProvider x:Key="TotoObject" ObjectType="{x:Type local:ContactManager}" MethodName="GetContactList" /> </Window.Resources> <Grid> <ListBox ItemsSource="{Binding Source={StaticResource TotoObject}}"></ListBox> </Grid>

Asynchronisme et ObjectDataProvider

L' objectDataProvider possède,  un attribut permettant de charger de manière asynchrone les objets. Cette propriété nommé "Asynchronous" s' utilise comme suit :

<ObjectDataProvider x:Key="TotoObject" ObjectType="{x:Type local:ContactManager}" MethodName="GetContactList" IsAsynchronous="True"/>

Ainsi vous pouvez lancer votre fenêtre, la manipuler pendant que les données se charge dans un thread différent (c'est le threadPool qui est sollicité pour réaliser cela) ce qui permet bien sur de ne pas bloquer l' interface durant de long chargements .

Alors en conclusion , dans quel contexte utilise-t-on un ObjectDataProvider  ?

  • Vous ne souhaitez pas lier la source de données directement,
  • Vos listes à Binder sont fournis par des classes tierces qui les exposent via des méthodes (Factory par exemple),
  • Vous avez la nécessité d' instancier des objets en XAML via leurs constructeurs paramétrés,
  • Vous souhaitez réaliser des chargements asynchrones de vos données (d'autres méthodes existent, bien sur, mais l'objectDataProvider est un moyen simple d' y parvenir).

Musa.

3 commentaire(s)
Classé sous :

Bonjour à tous

après plusieurs mois d' hésitation je n' ai pu résister à l' appel de l' ouverture d' un blog technique.

Alors technique oui mais pas que, en effet, je suis consultant sur les technos Microsoft et la majeure partie de mon travail consiste à accompagner des clients dans le développement d' application avec les technologie .NET.

Mais une partie de mon temps est aussi consacrée à la gestion de projet  (et la R&D comme tout bon consultant :o) ).

 

C'est pourquoi ce blog aura une tendance Technico - Chef de projet.... Mais surtout je vous l' assure très technique....

 

Les technos que j' aborderais le plus : WPF, Silverlight, .NET en générale et bien sur Visual studio Team System (vous voyez c'est le coté chef de projet là !).

 

Je tiens d' ailleurs à remercier Redo et Nix pour l' ouverture de ce blog



Les 10 derniers blogs postés

- Etes-vous yOS compatible ? (2/3) : la nouvelle plateforme Yammer–Office 365–SharePoint par Le blog de Patrick [MVP SharePoint] le 04-22-2014, 09:27

- [ #Yammer ] [ #Office365 ] Quelques précisions sur l’activation de Yammer Entreprise par Le blog de Patrick [MVP SharePoint] le 04-22-2014, 09:03

- Après Montréal, ce sera Barcelone, rendez-vous à la European SharePoint Conference 2014 ! par Le blog de Patrick [MVP SharePoint] le 04-19-2014, 09:21

- Emportez votre sélection de la MSDN dans la poche ? par Blog de Jérémy Jeanson le 04-17-2014, 22:24

- [ #Office365 ] Pb de connexion du flux Yammer ajouté à un site SharePoint par Le blog de Patrick [MVP SharePoint] le 04-17-2014, 17:03

- NFluent & Data Annotations : coder ses propres assertions par Fathi Bellahcene le 04-17-2014, 16:54

- Installer un site ASP.net 32bits sur un serveur exécutant SharePoint 2013 par Blog de Jérémy Jeanson le 04-17-2014, 06:34

- [ SharePoint Summit Montréal 2014 ] Tests de montée en charge SharePoint par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 20:44

- [ SharePoint Summit Montréal 2014 ] Bâtir un site web public avec Office 365 par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 18:30

- Kinect + Speech Recognition + Eedomus = Dommy par Aurélien GALTIER le 04-16-2014, 17:17