Voilà, VS2010 est en RC, je n’ai pas pu m’empêcher de l’installer sur ma nouvelle machine :p. je vais tenter d’écrire un ou deux postes sur .NET 4.0 dans les jours qui viennent. Je n’abandonne pas mon apprentissage de WPF mais j’ai dû récemment me reconcentrer sur ASP.NET pour une mission où je devais “jqueryser” une appli web. Là, je me dis qu’il est tant de se tenir prêt pour le .NET 4.0, la date de sortie en boîte approchant.

Bon alors, pour commencer, on télécharge VS2010, cela se passe ici.

Qu’y a t’il de nouveau dans VS2010 ?  pas mal d’ajouts :

  • l’éditeur de code qui devient vectoriel.
  • la refonte de la vue hiérarchique.
  • le sur-lignage automatique.
  • l’auto-génération d’objets.
  • la génération de nouveaux rapports de performance.
  • et bien d’autres fonctionnalités,…

Avec .NET 4.0, arrive aussi ASP.NET 4.0, ASP.NET MVC 2, le très prometteur Windows Workflow 4.0,…

Pour commencer avec VS2010, un petit truc sympa, personnaliser la page d’accueil de votre VS2010. C’est très simple, vous vous rendez sur C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\StartPages\en, vous allez voir des fichiers XML, ainsi que l’image de présentation VS 2010, donc soit vous changez les fichiers XML, pour par exemple rajouter des liens utiles, une description sur un projet,… Ici, je vais simplement changer l’image et rajouter le logo de ma compagnie. N’oubliez-pas d’être administrateur sur le dossier pour pouvoir modifier à votre grè.

Après avoir modifié l’image et enregistré les modifications, vous relancez VS 2010 et *tadam* :

vs2010homepage
Bon voilà, c’était l’apéritif avant les plats principaux…

Comme je vous l’avez écrit dans mon précédent article, quelques prérequis doivent être connus afin de continuer à bien notre quête. En effet, le chemin sera long avant de maîtriser tous les tenants et aboutissants de cette matière vaste. Selon l’adage, “petit train ira loin”, je m’efforcerai le plus possible à rentrer dans les détails, quitte parfois à sortir de notre but initial. Prenons par exemple cet article, il traîte du databinding, bien qu’il se détourne de notre but (Composite Application Guidance), il pourra néanmoins vous servir pour comprendre le principe du binding dans wpf et silverlight (ce qui pourra vous servir pour d’autres projets). Et finalement, ce n’est pas cela être Agile ?  Se développer de manière indépendante et ensuire recoller les morceaux (ici l’apprentissage) afin de former un tout (la connaissance).

Qu’est ce que le databinding ?

Selon Ms, c’est la méthode qui permet de lier les composants UI (textbox, listbox,…) à la couche métier. En effet, si les données changent dans la couche métier et que le binding est correctement configuré, les éléments UI se mettront à jour automatiquement. Mais l’inverse est également vrai, si l’utilisateur rentre une valuer dans un textbox, par le binding, le changement sera automatiquement reflété dans la couche métier.

Concept du databinding :

ms752347_databindingmostbasicen-usvs_90fig 1 (from MSDN)

  • La databinding est le lien entre l’objet cible (target en anglais) et l’objet source. Chaque Binding possède quatre composants, un “binding target object” (l’objet cible), une “property target” (la propriété cible de l’ojet cible), un “binding source object” (la source de donnée), et un “path” c’est à dire un chemin vers la valeur se trouvant dans l’objet source.

Par exemple, si vous vouler “binder” le contenu d’un Textbox à la propriété Nom d’un objet Humain, votre objet cible sera la TextBox,
la propriété cible sera la propriété Text de l’object Textbox, la valeur à exploité (le “path”) est la propriété source Nom de l’objet source Humain.

  • La propriété de l’objet cible que nous voulons manipuler est un “Dependency Property”  traduction une propriété dépendante. Ceci afin de pouvoir lier cette propriété par databinding. Presque toutes les propriétés des éléments UI (textbox, listbox) sont des “Dependence Property” sauf les “Read-Only”. En effet, ces classes dérivent tous du DependencyObject class (voir ici et ici) qui permet de définir des DependencyProperty qui support le binding.
  • L’objet source n’est seulement un object CLR personnalisé (un object comme que vous avez créé comme, par exemple, humain), cela pourrait être tout aussi bien, des objets qui proviennet d’ADO.NET, de webservice ou encore, d’un noeud XML qui contient des données.

A noter que pour créer ces liens (ce databind), vous utilisez des BindingOjbects, c’est grâce à ces objets que le lien peut se faire.

La direction du flux de donnée :

dataflowfigure 2 (from MSDN)

En effet, le flux de données à un sens, comme l’on peut le voir dans la figure 2. Il y a un sens aux flèches. Le flux de donnée va d’un object source vers un objet cible. La propriété name du textbox pourrait être tout aussi bien être la cible que la source. Ce n’est plus la propriété text du TextBox qui se “remplit” de la proriété Nom de l’objet Humain mais c’est maintenant la propriété text du TextBox qui “remplit” la propriété Nom de l’objet Humain. Ceci implique donc trois sens pour les flux de données (noms donnés en anglais).

  • One Way: la propriété cible change selon les données de la propriété source mais l’inverse n’est pas vrai. Ceci convient pour les contrôles de type Read-Only.
  • Two Way: le flux de données se propagent dans les deux sens, la propriété est tantôt une propriété source, tantôt une propriété cible. Générallement, nous utiliserons Two Way pour les objets de type formulaire. Par exemple, la propriété Text du TextBox et la propriété IsChecked de l’objet CheckBox est par défaut Two Way.
  • OneWayToSource: il est l’inverse de OneWay, il met à jour la propriété source lorsqu’il y a un changement dans la propriété cible.
  • One Time (ne se trouve pas dans la figure 2): Initialise la propriété source mais les changements futures ne seront pas propagés. Ce type de “binding” (de lien) est utilisé si vous voulez prendre un instantané de l’état de votre couche métier. Il est plus ou moins équivalent au OneWay mais est plus performant, il est donc à utiliser lorsque les valeurs sont statiques.

Comment détecter des changements dans l’objet source (ceci uniquement pour OneWay et TwoWay) ?

L’objet doit implémenter un méchanisme de notification, en implémentant l’interface INotifyPropertyChange (nous verrons pourquoi plus tard).

Que déclenche un changement dans la source ?

Les databindings qui sont TwoWay et OneWayToSource doivent être attentif aux changements de la propriété cible afin de les propagers vers l’objet source. Le sens du flux de données est assuré par la propriété Mode de l’objet Binding.

Cependant, est-ce que la valeur de votre objet source (par exemple la propriété Nom de l’objet Humain) change t’elle lorsque vous être entrain de changer cette valeur (lors de la saisie dans le TextBox) ou après que vous ayez fini (de changer la valeur du TextBox) ?

En fait, c’est la propriété UpdateSourceTrigger qui détermine ce qui va déclencher la mise à jour de l’objet source.

dataflowupdatesourcetriggerfigure 3 (from MSDN)

Si nous regardons la figure 3, les points représentés aux extrémités des flèches illustrent le rôle de l’UpdateSourceTrigger.

Si l’UpdateSourceTrigger à la valeur “PropertyChanged”, dès que la valeur dans le textbox changera, la valeur de l’object source changera également. Par contre, si l’UpdateSourceTrigger à comme valeur “LostFocus”, la valeur de l’objet source sera propagée lorsque nous nous retirerons du TextBox (passer à un autre textbox par ex.). La valeur par défaut de UpdateSourceTrigger dépend de l’objet. Pour un TextBox cette valeur est, par défaut, LostFocus. En effet, si nous devrions propager la valeur à chaque fois que nous entrons une lettre dans le textbox, les performances diminueraient, c’est pour cette raison que la valeur par défaut de UpdateSourceTrigger est LostFocus et non pas PorpertyChanged.

Il existe également pour le textbox une troisième valeur pour UpdateSourceTrigger, Explicit, utilisée par exemple pour mettre à jour la valeur seulement lors d’un clique de bouton par l’utilisateur (plus d’info sur l’UpdateSourceTrigger : ici ).

Créer un Binding :

Passons au pratique, nous allons établir un lien à l’aide de l’objet binding. Je ne vais pas vous le cacher, pour commencer je vais prendre un exemple MSDN.

Nous avons un object source qui est une classe MyData, elle a une propriété string ColorName dont la valeur est rouge. Nous voulons lier la couleur du background à la valeur ColorName de MyData.

Voici le code en XAML : pour plus d’info sur la syntaxt du binding (ici)

xaml_exemple11

Et voici le code C# :

cexmple1

Ce binding est un binding OneWay en effet, la propriété background du TextBox est par défaut OneWay.

databinding_backgroundtextboxtfigure 4

Le background property de l’object textbox est de type brush, néanmoins nous lui passons un string, ceci fonctionne par une conversion implicite (plus d’info ici).

Spécifier le Binding Source :

Ici le binding source est défini spécifiant une valeur au DataContext. Le DataContext du Window1 est l’objet MyData. TextBoxt hérite de ce datacontext par l’objet Window1 (son parent). En donnant le chemin vers la propriété qui doit être lié dans le background du textblock. Celui-ci sera où prendre ces données. Si nous ne définissons aucune valeur pour le datacontext, le background du textbox ne prendrait pas la couleur rouge.

Nous obtenons alors le résultat suivant :

appli1

Il est intéressant de définir le datacontext dans un niveau parent lorsque vous voulez utilisez ce contexte pour plusieurs enfants. Dans le cas contraire, vous pouvez définir ce contexte rien que pour l’élément que vous voulez lier.

La Classe BindingExpression :

Comme défini plus haut, Binding class est la classe haut niveau pour définir un Binding. Le BindingExpression qui est une sous-jacente de l’objet Binding, cet objet permet de maintenir la connexion entre l’objet source et l’objet target. Un objet Binding contient toute l’information et peut être partagée par plusieurs BindingExpression. Une BindingExpression est une expression d’instance qui ne peut partager ses informations, elle contient toute l’information de l’instance du Binding.

bindingexpression

myDataObject est une instance de la classe MyData, myBinding est la source de l’objet Binding, MyData est une classe qui contient la propriété string MyDataProperty. Cet exemple lie le contenu text d’une instance de TextBLock myText vers MyDataProperty.

Dans ce cas, vous pouvez réutiliser l’objet myBinding, par exemple, en liant à un propriété d’un TextBlock. A ce moment, il n’y aura qu’un objet Binding mais deux instances de BindingExpression qui se partage l’objet Binding.

DataConversion :

Dans l’exemple précédent, la propriété background du Texbox est lié à une propriété string avec la valeur « Red ». Cela fonctionne car le type Brush est capable de convertir un string en un objet Brush .

dataconversionfigure 5

Comme l’on peut remarquer sur la figure 5, le Type Brush à une conversion par défaut qui permet de convertir un objet de type string en objet de type Brush.

Que se passerait t’il si notre objet source avait un type Color pour la propriété ColorName. Nous devrions implémenter l’interface IValueConverter (pour plus d’info sur IValueConverter, cela se passe ici). De cette manière l’objet binding sait comment convertir un objet Color en objet de type SolidColorBrush.

ivalueconverter

Par l’implémentation de cette inferface, notre schéma devient alors :

dataconversionwithivalueconverterfigure 6

Généralement, pour les types cible connus, la conversion par défaut devrait fonctionner. En cas de doute, vous devriez implémenter l’interface IValueConverter.

Voici une liste de cas où l’utilisation de cette interface est préconisée :

  • Vos données devront être affichées différement suivant la culture que vous utilisez. Vous pourriez implémenter un convertisseur de change et/ou un convertisseur de date utilisée par une certaine culture.
  • La valeur qui est manipulée ne servira pas à changer la propriété Text du Textbox mais d’autres valeurs comme une source d’image, la couleur ou le style de text affiché. Les convertisseurs peuvent alors être utilisés en convertissant des propriétés qui ne semblerait pas lié entres-elles. Comme par exemple, lier la valeur d’un textbox à une couleur de fond pour une cellule d’un tableau.
  • Plus d’un contrôle ou même plusieurs propriétés d’un contrôle peuvent être liées à une même source. Générallement, le “Binding” primaire affichera le texte et d’autres types de “Binding” posséderont certaines particularités sur la manière de relier les éléments entre eux, ceci tout en continuant à utiliser la même source d’information.
  • Dans le cas où nous utiliserons des MultiBinding , dans ce cas un propriété cible sera lié à une collection de Binding. Dans le cas d’un multibinding vous utiliserez l’interface IMultiValueConverter afin de produire une valeur finale à partir des valeurs contenues dans votre collection de Binding.

Binding to Collection :

Dans un Binding, un objet source peut être soit traité comme un simple objet dans lequel ses propriétés contiennent des données soit comme une collection de données d’objets polymorphiques groupés ensembles (comme le résultat d’une query provenant d’une base de données). Ici nous avons toujours utilisés des objets simples mais nous aurions pu utiliser des ItemsControl comme des ListBox, des ListView, des TreeView afin d’afficher des collections d’objets.

databindincollectionobjetfigure 6

Comme l’on peut remarquer dans le diagramme précédent, pour lié un ItemsControl à une collection d’objet, nous devons utiliser la propriété ItemsSource. ItemsSource est en quelque sorte le contenu du ItemsControl. Par défaut la direction du flux de donnée pour un ItemsControl sera OneWay.

Comment implémenter les collections ?

Vous pouvez utiliser n’importe quelles collections qui utilisent l’interface IEnumerable. Pour gérer un binding qui permettrait l’insertion, la suppression ou l’update de donnée automatiquement retranscrite dans l’UI, la collection doit implémenter l’interface INotifyCollectionChange. Cette interface permet d’exposer un évênement qui sera déclenché à chaque changement dans la collection.

WPF founit la classe ObservableCollection(T) qui est une implémentation d’une collection de donnée qui comprend l’interface INotifyCollectionChange. A noter que pour supporter le transfert de données entre l’objet cible et l’objet source, chaque objet dans la collection doit implémenter l’interface INotifyPropertyChange.

Avant d’utiliser votre propre collection, tentez d’utiliser ObservableCollection(T) ou l’une des classes de collection existante comme List(T), Collection(T), BindingList(T), parmis d’autres.

Collection Views

Une fois que votre ItemsControl est lié à un collection de données, vous pourriez vouloir trier, filtrer ou grouper les données. Pour faire cela, vous utilisez les collection views, qui sont des classes qui implémente l’interface ICollectionView.

Que sont les Collection Views ?

Une collection est une couche supérrieur par rapport à une “binding source collection” ce qui vous permet de naviguer et d’afficher la collection source triée, flitrée et groupée en queries, ceci sans changer la source sous-jacente elle même. Une “collection view” maintient également un pointeur vers l’item courant dans la collection. Si la collection source implémente l’interface INotifyCollectionChange, les changements seront déclenchés par l’évênement CollectionChanged  qui sera propagé aux vues.

Parce ques les vues ne changent pas la collection source adjacente, chaque collection source peut avoir plusieurs vues associées à elle. Par exemple, vous pourriez avoir une collection d’objets Task. Avec l’utilisation de vues, vous pourriez afficher la même donnée sous différentes vues. Par exemple, à gauche vous afficheriez les Tasks triées par priorité et de l’autre triée par date.

Commen créer une vue ?

Une façon de créer et utiliser une vue est d’instancier les objets vues directement et les utiliser comme source pour le binding.

collectionviewsourcefigure 7

listboxwithcollectionviewfigure8

Comme nous voyons dans l’exmple ci-dessus qui provient de MSDN, nous pouvons voir que le ListBox à pour Object source un CollectionViewSource lui-même lié à une liste d’objet AuctionItems . Vous pourriez réutililiser ce CollectionViewSource pour un autre type de contrôle, ce qui est important ici est de ne pas oublié de définir le x:Key dans la CollectionViewSource afin de que le contrôle puisse savoir où il va chercher ses données.

Le tableau suivant nous montre quels types de données (vue) sont crées comme CollectionView par défaut (IList -> ListCollectionView). Le résultat serait le même si nous utiliserions un CollectionViewSource afin de créer les CollectionViews.

sourcecollectiontypetocollectionviewtype

Utiliser une Default View

Spécifier une collection view comme un “binding” source est une des solutions pour créer et utiliser des collection view. WPF crée également une default collection view pour chaque collection utilisée comme source du binding. Is vous liez directement un contrôle, WPF la lie à sa vue par défaut. Cette vue par défaut est partagée par tout les “bindings” de la même collection, donc un changement fait à la vue par défaut par un contrôle lié ou du code (trier, filtrer,…) est reflétée dans tous les autres bindings de la même collection.

Collection Views avec ADO.NET DataTables

En vue d’améliorer les performances, les collection views pour ADO.NET DataTable ou les DataView délèguent le tri, les filtres au DataView. En conséquent, le tri et le filtrage sera partagé à travers toutes les collections du datasource. Afin de mettre en place le tri et le filtrage sur chaque collection view, vous devez initialiser chaque collection view avec son propre DataView object.

Sorting

Comme mentioné ci-dessus, les vues peuvent trier un collection. Comme il existe dans la collection adjacente, vos données pourraient ne pas être dans un ordre pertinant. La vue au dessous de cette collection adjacente vous permet d’imposer un ordre et de changer l’ordre par défaut, basé sur des critères de comparaison que vous définissez. Parceque c’est un client-based view des données, un scénario commun pourrait être un utisateur qui veut trier les colonnes d’un tableau suivant ses valeurs correspondantes. En utilisant les vues, ce tri personnalisé pourrait être appliqué, et ce, sans faire de changement dans la collection de la couche adjacente et sans devoir faire de query dans cette couche adjacente (plus d’info ici).

Voici un exemple de tri qui trie par Catégorie et par StartDate :

databindingsorting

Vous pouvez trouver un exmple de binding intéressant sur MSDN, ici.

Filtering :

Une vue peut également appliquer un filtre à une collection. Cela ne permet d’afficher qu’un sous-esemble d’une collection. Vous pouvez également trier sous des conditions personnalisées.

Voici un exemple de filtre qui provient de la démo fournie par MSDN.

filtering

The ShowOnlyBargainsFilter event handler

filtering2

Grouping :

Exepté pour les classe internal qui sont retranscrite en IEnumerable collection, toutes les collections views supporte la fonctionnalité de grouping. Ceci permets aux utilisateurs de subdiviser la collection dans la collection view dans un groupe logique. Les groupes peuvent être explicite, l’utilisateur fournit une liste de groups ou implitcit, les groups sont générés dynamiquement dépendamment des données.

Voici un exemple de fonction de grouping :

addgrouping

Pointer sur l’item actuel:

Les vues supportent également la notion d’item actuel. Vous pourriez naviguer à travers les objets dans une collection view. Pendant que vous naviguer, vous passez d’un item à un autre et un pointeur d’item vous permet de retirer les informations de l’item actuel.

Comme WPF est lié à une collection uniquement en utilisant une vue, toutes les liaisons vers les collections possèdent ce pointeur d’item. Quand vous liez à une vue le caractère “/” désigne le chemin vers la valeur actuel. Dans l’exemple suivant, le data context est une collection view, le premier binding est lié à la collection, le second binding est lié à l’item actuel de la collection et le troisième est lié à la propriété Description de l’item actuel.

Ex :

bindingpath

Le Master Detail Binding Scenario

La notion d’item actuel est utile pour le Master Detail Binding Scenario. Si nous regardons dans l’exemple ci-dessous où le contenu du ListBox détermine le contenu affiché dans le ContentControl. Vous pouvez déterminer le Master Detail Binding scenario en liant deux ou plus contrôle à une même vue.

masterdetailscenario

Ces deux contrôles sont liés à une même vue (listingDataView). Cette exemple marchera car lorsque un objet singleton (ici ContentControl) est lié à une collection view, il est automatiquement à l’item actuel (CurrentItem) de la vue. Si le list control n’est pas lié à un objet CollectionViewSource comme dans l’exemple, alors, vous devriez définir la propriété IsSynchronizedWithCurrentItem à “true” pour que cela fonctionne. L’exemple ci-dessous ne fonctionnerait pas si il n’utiliserait pas un template (voir prochain article).

DataTemplate :

Je reviendrai dans un prochaine sur l’utilisation de DataTemplate.

En attendant, voici une série de lien qui pourra vous être utiles :

http://msdn.microsoft.com/en-us/library/ms752347.aspx#specifying_the_binding_source

http://msdn.microsoft.com/en-us/library/ms752347.aspx#data_conversion

http://msdn.microsoft.com/en-us/library/ms752347.aspx#data_conversion

http://msdn.microsoft.com/en-us/library/dd458894.aspx

http://msdn.microsoft.com/en-us/magazine/cc163299.aspx

http://odetocode.com/articles/740.aspx

Questions générales :

1) C# supporte t’il l’héritage multiple ?

non

2) Pour qui sont disponibles les variables de type Protected comprises dans une classe ?

Pour toutes les sous-classes de la classe comprenant ces variables de type protected.

3) Est-ce que les variables de type privées sont héritées ?

Oui, mais elles ne sont pas accessibles. Bien qu’elles ne soient ni visibles et ni accessibles, elles sont héritées. Si vous voulez la rendre accessible aux sous-classes, vous devez utilisez une variable protected.

4) Décrire l’accessibilité du “protected internal” ?

Sera disponbile pour les classes qui se trouvent dans le même assembly et qui sont dérivés de cette classe de base.

5) De quelle classe sont dérivés tous les objets en .NET  ?

System.Object.

6) Que veut dire le terme “immutable” (immuable en Français) ?

Que la valeur de donnée (datavalue) ne peut-être changée. La valeur d’une variable peut être changée mais on est alors débarrasé de la valeur de données immuable et une nouvelle valeur de données a été créée.

7) Quelle est la différence entre les classes System.String et System.Text.StringBuilder ?

System.String est immuable. Stringbuilder a été créé pour manipuler des strings muables où des opérations sur ceux-ci peuvent être réalisées.

8 ) Quelle est l’avantage d’utiliser StringBuilder plutôt que String ?

Stringbuilder est plus performant si il faut manipuler un grand montant de string. String est immuable, c’est à dire qu’il recrée une nouvelle instance en mémoire à chaque fois que sa valeur change.

9) Pouvez-vous utiliser plusieurs types dans un System.Array ?

non

10) Quelle est la différence entre System.Array.CopyTo() et System.Array.Clone() ?

La méthode copy retourne un nouvel array (shallow copy (copie peu profonde, frivole)) d’objets contenant tous les éléments de l’array original. La méthode CopyTo() copie les éléments de l’array original dans un array existant. Les deux réalisent une copie peu profonde. Une copie peu profonde est le fait que le contenu (chaque élément d’un array) contiennent les références des mêmes objets que les éléments de l’array orginel. Une copie profonde (deep copy) aurait crée une nouvelle instance de chaque élément de l’objet orignal.

11) Comment trier un array dans le sens décroissant ?

On utilise la méthode Sort() et ensuite la méthode Reverse().

12) Quelle classe de collection peut-on utiliser pour accéder un de ses éléments par une clé d’accès ?

HashTable

13) Quelle classe se trouve à un niveau plus bas de Sorted List ?

Sorted HashTable

14) Dans un try catch, est-ce que le block “finally” sera exécuté si une exeption ne se produit  pas?

oui

15) Quelle est la syntaxe qui permet de saisir toutes les exeptions possibles ?

Un catch qui intercepterait les exeptions de type System.Exception. Si vous utilisez le catch par défaut (catch{}), cela aura le même effet.

16) Peut-on avoir plusieurs catch exécutés lors d’un même try ?

non, le contrôle sera exécuté dans la partie finally du try.

17) Quels sont les 3 parties d’une 3-tiers application ?

Presentation (UI), Business , Data

Question sur les classes :

1) Quelle est la syntaxe pour hériter d’un classe en C# ?

NomdelaClasseEnfant : NomdelaClasseParent

2) Pouvez-vous empêcher une classe d’être hériter par une autre classe ?

Oui en utilisant le keyword “sealed”.

3) Pouvez-vous permettre à une classe d’être héritable mais empêcher qu’une de ses méthodes soit “overrider” ?

Oui, il faut rendre la classe public et la méthode “sealed”.

4) Qu’est-ce qu’une classe abstraite ?

C’est une classe qui ne peut-être instanciée, c’est une classe qui peut être héritée et qui peut posséder des méthodes qui peuvent-être spécialisée  (”overrider”). Une classe abstaite est générallement une emprunte pour d’autres classes.

5) Quand devez-vous absolument définir une classe abstaite ?

- lorsqu’au moins une des méthodes est abstraite

- lorsq’une classe est elle-même héritée d’une classe abstraite et que toute ses méthodes abstraites héritées n’ont pas été redéfinir (”overrider”).

6) Qu’est-ce qu’une interface ?

Les interfaces, comme les classes définissent une série de propriété, méthodes, évênements. Mais contrairement au classe, les intefaces ne fournissent pas d’implémentation. Elles sont implémentées par des classes

7) Pourquoi ne pouvez-vous pas définir d’accesseur pour une méthode à l’intérieur d’une interface ?

Elles doivent toutes être publique, elles sont donc public par défaut.

8 ) Pouvez-vous hériter de plusieurs interfaces ?

oui, .NET supporter le multi-héritage d’interface

9) Pouvez-vous hériter de plusieurs interfaces qui ont des méthodes de même nom et même signature ?

Oui vous pouvez, mais il risque d’y avoir quelques problèmes. Si le compilateur est ok, cela devrait passer. PS : En testant, j’ai remarqué vous pouviez, en effet, hériter de plusieurs interfaces qui ont des méthodes de même nom, mais alors nous devons en choisir une qui sera public, les autres seront marquées privées. Enfin, je déconseillerais de réaliser ce genre de chose.

10) Quel est la différence entre une classe abstraite et une interface ?

Dans une inteface, toutes les méthodes sont abstraites, il n’y pas d’implémentation. Dans une classe abstraite, les méthodes peuvent-être non abstraite mais il n’y a pas d’implémentation. On peut, également, hériter de plusieurs interfaces alors qu’on ne peut hériter que d’une classe abstraite.

11) Quel est la différence entre une struct et une classe ?

Les Strucs sont des variables “value type” et sont donc sauvés dans la stack, ils augmentent la taille en mémoire mais augmentent les performances d’accès. Les structs ne peuvent pas être héritées.

Questions sur les méthodes et les propriétés :

1) Quel est le nom implicite du paramètre qui est passé à l’intérieur de la méthode/propriété set d’une classe?

La réponse est Value. Le type de la donnée value est définie par le type de la propriété qui est déclarée.

2) Que veut dire le keyword “vitrual” devant une propriété et/ou une méthode ?

Que la méthode et/ou propriété peut être redéfinie (”overrider”)?

3) En quoi la redifinission (”overrider”) d’une méthode est telle différente de la surchage d’une méthode (overload) ?

Quand vous redéfinissez une méthode, vous changer le comportement de la classe dérivée (vous spécialisez la méthode à sa classe concrète). La surchage d’une méthode entraîne juste le fait d’avoir plusieurs méthodes avec le même nom dans une classe. Ces méthodes ne possèderont pas la même signature.

4) Pouvez-vous redéfinir (”override”) une méthode et la rendre statique, si celle-ci ne l’était pas dans sa classe de base ?

Non, la signature de la méthode doit rester la même (on ne peut changer override que par virtual).

5) Quelles sont les différentes manières de surcharger une méthode ?

Différents paramètres (data type), nombre de paramètres différents, ordre dont les parramètres sont passés.

6) Si une classe de base à un nombre certain de constructeurs surchargés, et la classe héritée a un certain nombre de constructeurs surchargés également, pouvez-vous forcer l’appel du constructeur de la classe de base depuis la classe spécifique?

oui, ajouter “:base()” et entre les parenthèses, les paramètres que vous voulez réutiliser de votre classe de base.

Events and delegates :

1) Qu’est qu’un delegates ?

Un delegate encapsule un référencement vers une méthode.

2) Qu’est ce qu’un multicast delegates ?

Un délégate qui a plusieurs méthodes référencées (handler), toutes ces méthodes seront appelées.

XML - Documentation :

1) XML est-il sensible à la case ?

oui

2) Quelles sont les différences entre // , /// ,/* */ ?

// => commentaire sur une ligne

/// => commentaire en XML

/* */ => commentaire multi-ligne

3) Comment générer de la documentation depuis des commentaires appartenant à un fichier C# avec un compiler en ligne de commande ?

Compilez le avec la balise /doc

Debugging et questions sur les tests :

1) Quel(s) outil(s) de debugging est fourni avec le sdk .NET ?

- CorDBG : command line debugger. Pour utiliser le CordDBG vous devez compiler en ligne de commande avec l’attribu /debug.

- DbgCLR : le debugger en mode graphique, utilisé par Visual Studio.

2) Que fait la méthode Assert() ?

En debug, assert prend une condition booléene comme paramètre et montre la boîte de dialog error si la condition est fausse. Le programme s’exécutera si la condition est vrai.

3) Quelle est la différence entre la classe debug et la classe trace ?

La documentation semble la même, utilisez la classe debug pour debulg build, utilisez la classe Trace pour les builds debug et release.

4) Où la sortie de TextWriterTraceListener est-il redirigé ?

Soit dans une console, soit dans un fichier, dépendant des paramètres qui lui sont passés.

5) Comment débugger une application ASP.NET ?

Attachez le process aspnet_wp.exe au débugger dbgclr;

6) Quels sont les trois types de test vous devriez tester dans vos tests unitaires ?

- Un cas de test positif : donnée correcte, sortie correcte.

- Un cas de test négatif : donnée incorrecte ou manquante et exécution propre.

- Un cas d’exeption : vérifier si les exceptions sont gérer correctement.

7) Pouvez-vous changer la valeur d’une variable pendant que vous debugger une application C# ?

Oui, si nous débuggons via Visual Studio .NET, se rendre sur Immediate Window.

ADO.NET et Database :

1) Quel est le rôle de la classe DataReader dans ADO.NET ?

Un DataReader retourne un ensemble de row, read-only et forward-only à partir d’un datasource.

2) Quels sont les avantages et les inconvénients des data provider fourni par Microsoft dans ADO.NET ?

SqlServer.NET data provider une solution performante et robuste pour accéder à un serveur SQL. Cependant microsoft fournit une classe OLE-DB.NET qui permet d’accéder aussi-bien des base de données Oracle, DB2,… Cependant, cette couche n’est pas aussi performante et efficace que la couche d’accès pour Sql Server.

3) Quel est le caractère de remplacement (wild card) en SQL ?

Réponse : %, utiliser avec LIKE dans les query SQL.

4) Expliquez les règles d’or ACID pour les transactions ?

Une transaction doit être:

- Atomic : cette unité de travail ne doit pas dépendre des transactions précédentes ou futures.

- Consistent : Les données doivent être conformes et un système de roll-back doit être mis en place. Il ne dois pas y avoir de valeur “in-between”, le cas ou une partie a été mise à jour et pas l’autre.

- Isolated : aucune transaction ne voit le résultat intermédiare de la transaction actuelle.

- Durable :  La donnée doit persistée si elle est conforme même si par après le système plante.

5) Quels types de connections supportent SQL Server ?

Windows Authentication (via Active Directory) et SQL authentication (via SQL Server avec un login et un mot de passe).

6) Entre windows authentication et sql server authentication, lequel est “trusted”, lequel ne l’est pas ?

Windows authentication est trusted car le usernam et le password est vérifié par Active Directory, Sql server est untrusted car il est le seul à participer

7) Qu’est ce que définit le “initial catalog” dans le connexion string ?

le nom de la database

8) Que fait la méthode Dispose avec l’objet Connection ?

il le supprime de la mémoire.

9) Quel est le prérequis pour un connection pooling ?

La procédures multiples doivent accepter de partarger la même connection, tout les paramètres doivent être les mêmes (paramètres de sécurité inclus). Le connection string doit être identique.

Assembly :

1) Quels sont les possibilités pour déployer un assembly ?

un MSI Installer, une archive CAB, la commande XCOPY

2) Qu’est ce qu’un assembly satellite ?

Lorsque vous écrivez une application multi-lingue et/ou multi-cultures en .NET, vous voulez distribuer le core de l’application séparrément de ces modules localisés. Les assembly localisées sont alors des assembly satellite.

3) Quels sont les namespace à incorporer pour une application localisée ?

System.Globalization et System.Ressources

4) Quelle est la plus petite unité d’exécution en .NET ?

un assembly

5) Quand devez-vous appeler le Garbage Collector en .NET ?

Normalement jamais. Néanmoins, vous pouvez appeler le Garbage collector lorsque vous vous débarasser d’ objets conséquents en mémoire dont vous n’avez plus l’utilité.

6) Quel nom porte l’action de convertir un value-type en reference-type?

Boxing

7) Que se passe t’il en mémoire lorsque vous “boxez” une valute-type en reference type ?

L’objet créé par boxing se mémorisera dans le heap (passage du stack au heap). Unboxing est l’opération inverse, il convertit un type référence en un value-type, c’est à dire passage du heap au stack.

Conclusion :

Je rajouterai au fur et à mesure de nouvelles questions, mon but étant de faire une sorte de FAQ sur le C# à connaître avant de passer une interview.

Pour commencer, précisons que C# ne permet pas (contrairement à VB) des conversions implicites avec perte de précision. Par contre, C# autorise les conversions implicites si le type destinataire peut s’accomodé de toutes les valeurs du type source. Ceci est appelé une “widening conversion”.

Voici un exemple de “widening conversion” :

int i = 1;

double d = 1.000001;

d = i ; // convertion OK

Si le type source à un range et une précision plus grande que celle du destinataire on parle alors de “norrowing conversion”. Ceci requiert une conversion explicite. Ce type de conversion est source d’erreur si la valeur source dépasse le range du type destinataire. Dans ce cas, si la conversion entre ces types n’est pas définie, vous recevrez une erreur de compilation.

Autre type de casting donc, le norrowing conversion :

double d = 1.000001;

int i = 1;

i = int (d);

Boxing : C’est convertir un type valeur (int, double, float,…) en un type référence. Ci-dessous nous convertissons un int (type valeur) en un objet (type référence).

int i = 124;

object o = (object) i ;

UnBoxing : C’est convertir un type objet en un type valeur. Convertir un objet en int.

object o = 123;

int i = (int)o;

La pratique du Boxing et de l’Unboxing est assez coûteux en performance et vous devriez éviter de l’utiliser trop souvent à l’intérieur de tâches répétitives. Le boxing intervient également lorsque l’on appele une méthode virtuel d’une structure ou d’un type valeur qui hérite de System.Objet, comme ToString(). Les conseils suivant évitent les boxing non-nécessaires

  • Implémenter des méthodes spécifiques par type que nous voulons utiliser. Ceci est utile lorsque cette méthode doit être capable d’interpréter plusieurs types de valeurs.
  • Utiliser les génériques plutôt que de coder à partir du system.object.
  • Override les méthodes ToString, Equals, GetHash virtual lorsque l’on définit une structure.

Comment implémenter la conversion pour un type personnalisé ?

  • Définir les opérateurs de convesion pour simplifier le narrowing  (perte de taille et précision) et le widening (augmentation de la taille et de la précision) entre les types numériques.
  • Override la méthode ToString pour définir les conversions vers le type string. Override la méthode Parse pour les conversions depuis string.
  • Implémentez System.IConvertible pour permettre la conversion à travers System.Convert. Utilisez cette technique pour définir la conversion spécique aux cultures.
  • Implémentez une classe TypeConverter qui permet la conversion lors du design-time pour utiliser les propriétés window de Visual Studio.

Vous pouvez également définir les opérations implicit et explicit pour vos classes personnalisées, de cette manière vous autoriserez le casting (widening et narrowing) pour vos classes.

Voici un exemple d’implémentation de casting pour une classe personnalisée :

customstruccasting

Et l’implémentation :

customstruccastingapp

J’espère que ses explications vous serviront à mieux comprendre les conversions en C#. Si vous avez des remarques, n’hésitez-pas à m’en faire part.

Voici un tableau que j’ai trouvé dans un cours C# de Serge Tahé se trouvant sur le net (http://tahe.developpez.com/dotnet/csharp/). Il me semble bien représenté et c’est dans ce but que je vous le fais partager.

De plus, j’avoue que j’ai tendance à oublier les valeurs extrêmes que nous avons parfois besoin pour nos tests unitaires.

Voici le tableau :

typededonnee

A coté du type, vous trouverez (s) si celle-ci est une structure et (c) si celle-ci est une classe.

N’oubliez pas que le compilateur .NET est optimisé pour la manipulation de type INT32. De même, pour les types décimaux, les variables de type double sont conseillées car optimisées par le hardware.

N’oubliez pas également la différence entre un variable de type structure et une variable de type classe.

  • Une variable de type Structure se manipule via ses valeurs.
  • Une variable de type Classe se manipule via son adressage (référence à l’objet).

Une structure et une classe ont tous deux des attributs et des méthodes.

Voici une petite application qui utilise ses concetps. A noter, la méthode sizeof() qui nous sert à déterminer la taille du type.

datatypeapp

Déclaration d’un constante : Si vous voulez déclarer une constante, vous utiliserez le keyword const, ceci entrainera la non-modification de votre variable.

Exemple :

const int c = 10;

Attention le readonly keyword est différent de const. Un const ne peut être initializé qu’à la déclaration de la variable. Un type readonly peut s’initializer à la déclaration mais aussi au sein d’un constructeur. Egalement, un champ const est une constante compile-time tandis qu’un champ readonly peut être utilisée pour une constante run-time.

Nous pouvons alors écrire :

public static readonly uint MaVariable = (uint) DateTime.Now.Ticks;

Le mot clé VAR:

Var ne veut pas dire que la variable n’a pas un type précis. La variable à le type de la donnée qui lui est affectée. L’initialisation est ici obligatoire afin que le compilateur puisse en déduire le type de variable.

Une variable typée implicitement ne peut pas changer de type par la suite.

Hier, dans le cadre de mon travail, une personne me demande qu’est ce que le polymorphisme ? Je tente de lui expliquer par mes mots et j’ai la honte de m’embrouiller un peu. C’est vrai que l’on utilise tous ce principe de l’orienté objet mais j’ai été surppris de voir qu’autour de moi, je n’étais pas le seul à m’embrouiller lors des explications.
Le polymorphisme est un principe général de l’Orienté objet, il n’est pas propre au C#.

L’explication façon analyste (UML) est la suivante :

Le polmymorphisme est le fait qu’un même message puisse être interprété de differentes façons en fonction de l’object qui recoit ce message.

Le message dans cette définition est un appel vers un méthode en C#.

Pour comprendre, prenons un exemple concret :

Modélisons le problème suivant :

  • Les chiens et les chats sont des animaux.
  • Je sais qu’un animal s’exprime mais je ne sais pas comment il s’exprime.
  • Je sais que le chien aboie.
  • Je sais que le chat miaule.

Prenons une classe de base :

animal

Maintenant modélisons la classe Chat et la Classe chien.

chat

chien

Maintenant que nous avons modélisé la superclasse et les classes concrètes qui héritent de cette superclasse.

Nous pouvons utiliser ces classes concrètes. Par exemple créons une liste d’animaux comprenant des chiens, des chats et des animaux non-identifiés.

implementation

Dans ma liste d’animaux, peu importe que la classe concrète soit un Chien, un Chat ou un animal, ce que je récupère est un Animal. Comme la méthode MakeNoise() est définie dans le classe Animal, je peux donc l’invoquer. Si c’est un chat qui a été instancié, le chat miaulera. Si c’est un chien, celui-ci aboiera. Ci ce n’est ni l’un, ni l’autre, nous ne serons pas comment il fait du bruit car le cri dépend de l’animal.

Et voici le résultat de notre exemple :

result

En conclustion, le polymorphisme évite de tester le type d’objet concret que l’on manipule, lorsque l’on exécutera un de ses méthodes spécialisées, c’est le polymorphisme qui exécutera le code spécifique (ceci grâce au balise virtual et override).

Routed Event :

Ce qui est difficile pour moi qui vient du monde ASP.NET, c’est le nombre de nouveaux concepts qu’il faut apprendre avant de maîtriser WPF. En effet, il y a plusieurs concepts nouveaux en WPF. Les dependency property (qui servent pour le databinding, le styling,…) mais également les RoutedEvents et les RoutedCommand. En effet, WPF n’utilise pas le système standard des événements mais une version plus puissante. Pour qu’un objet puisse avoir la possibilité de bénéficier de ces nouvelles fonctionnalités, il doit obligatoirement dérivée de la classe UIElement.

Généralement, vous utilisez les Routed Event sans vous en rendre compte. Par exemple, vous ajoutez un bouton dans un objet Windows, vous le nommez MyButton, vous double-cliquez sur ce bouton, il va créer tout ce qu’il vous faut pour que vous puissiez créer l’action que vous désirez déclencher lors de l’évènement click de l’élément bouton. Vous ne verrez alors aucune différence entre WPF et Winforms ou ASP.NET.

Prenons le bouton XAML :

routeevent1

 La déclaration en XAML pour se «  raccorder » à l’événement  est juste une propriété Click du contrôle Bouton. En fait, ce raccordement se trouve dans un « compile-time-generated » de la classe partiel de votre Windows (en gros le framework fait tout pour que ce soit transparent pour vous). Pour visualiser tous ces appels « automatiques », faites un clique droit sur la méthode InitializeComponent() de votre Window. Si vous descendez un peu vous verrez les lignes suivantes :

routeevent2

La classe partielle est générée à partir du XAML lors de la compilation et contient tous les éléments XAML qu’a besoin le « design-time compilator ».

Si nous regardons de plus près le code de cette classe partiel, le Click handler ressemble à ceci :

routeevent3

Ce qui ressemble fortement à ce que vous connaissez déjà dans le monde .NET. La seule chose différente est que vous n’utilisez plus EventArg comme type d’argument mais RoutedEventArgs.

Mais qu’y a-t-il de si différent ? Avant de vous expliquer cela, vous devez comprendre la composition des éléments du modèle WPF.

WPF, structure en Arbre :

Si vous démarrez un nouveau projet WPF, vous allez directement vous retrouver avec un code qui ressemble à ceci :

routeevent4

Chaque élément représente une Runtime instance correspondant à un type .NET, et nous remarquons la structure en arbre (logical tree) qui impose une hiérarchie entre les éléments. De plus, la plupart des éléments en WPF sont dit soit ContentControl ou ItemsControl .Ce qui veut dire qu’ils peuvent comprendre des éléments enfants.

Par exemple, un Bouton est un ContentControl , il peut avoir une hiérarchie complexe d’enfant en dessous de lui. Nous pourrions alors écrire ceci :

routeevent5

L’application ressemblerait alors à quelque chose du genre :

routeevent6

Comme vous en doutez, l’arborescence de cette structure peut devenir extrêmement complexe. Mais n’oubliez pas qu’en WPF tout ce que vous voyez n’est pas nécessairement ce que vous avez au Runtime.

Ci-dessous, l’arbre logique de notre bouton contenant un stackpanel  comprenant lui-même une image et un textblock.

routeevent7

Vous pouvez remarque que l’élément windows (EventsWindows) englobe son contenu dans un Border et un AdornerDecorator et présente le contenu à l’intérieur d’un ContentPresenter. Le bouton fait de même en englobant son contenu avec un objet ButtonChrome et présente son contenu dans un ContentPresenter.

Quand je clique sur le bouton, je pourrais ne pas cliquer du tout sur l’élément Bouton mais sur un de ses enfants dans l’arbre logique, peut-être même un qui n’est même pas dans cette structure en arbre (ButtonChrome). Par exemple, je clique avec ma souris sur le coin supérieur de l’image contenu dans le bouton. Cette action se manifeste comme un évènement MouseLeftButtonDown à l’intérieur de l’élément image ; mais nous voudrions que celui-ci soit transmis comme évènement click au niveau de l’élément bouton. C’est ici que rentre en jeux les RoutedEvents.

Les évènements routés :

Bien comprendre la structure en arbre des éléments dans WPF est primordial pour bien comprendre les routed events. En effet, les routed events sont routées par défaut sur cette structure en arbre. Ils supportent également les RoutingStrategy de type Bubble, Tunnel et Direct.

Bubble :

Bubble est le plus commun, l’évènement se propagera vers le haut de la structure à partir de l’élément source jusqu’à ce qu’il soit géré où qu’il ait atteint l’élément racine. Cela vous permet de gérer un évènement par un objet qui se trouve plus éloigné dans la structure que votre élément source. Par exemple, vous pourriez attacher un Button.Click handler sur l’élément Grid compris dans l’objet Button lui-même. Les évènements Bubble ont juste leur nom qui indique leur action (par exemple, MouseDown).

L’évènement Tunnel, lui, part de l’élément racine et traverse vers le bas les éléments de la structure jusqu’à ce qu’il soit pris en compte où qu’il atteigne l’élément source de l’évènement. Cela permet d’intercepter des évènements en amont et de le manipuler avant que celui-ci n’atteignent l’élément source. Les évènements Tunnel sont généralement nommés par le préfixe Preview par convention (PreviewMouseDown).

Les évènements Direct, eux, se comporte de la même manière que les évènements normaux dans le Framework .NET. Le seul handler possible pour ce type d’évènement est un delegate qui souscrit à cet évènement.

Généralement, pour chaque évènement Tunnel correspond un évènement Bubble. Dans ce cas, l’évènement Tunnel est déclenché en premier ; ils commencent de l’élément racine et descend vers l’élément source en cherchant un handler. Une fois qu’il a été intercepté ou a atteint l’élément source, le Bubble event correspondant est lancé. Partant de l’élément source et remontant vers le haut de la structure cherchant un handler.

A noter qu’un évènement Bubble ou Tunnel ne se stoppent pas parcequ’un EventHandler a été appelé. Si vous voulez stopper un évènement Bubble ou Tunnel, vous devez marquer l’évènement comme « handled » en utilisant l’argument évènement qui lui est passé.

routeevent8

Le fait que l’évènement stoppe lorsque celui-ci est marqué «handled » n’est pas totalement vrai. En réalité le processus continue en arrière scène et vous pourriez intercepter de nouveaux cet évènement en « overridant » UIElement.AddHandler method qui possède un flag permettant de continué la propagation de l’évènement, c’est-à-dire  « Appelle moi-même si l’évènement est marqué comme handled ».

Voici comment spécifier ce flag :

routeevent9

Le premier paramètre est le RoutedEvent que vous voulez manipuler, le second est une fonction delegate à la méthode qui manipulera l’évènement (qui devra posséder une signature correcte pour le delegate de cet évènement), le troisième paramètre indique si oui ou non vous voulez être notifié (même si un autre handler a marqué cet évènement comme « handled »). L’élément du quel vous appelez AddHandler est celui qui surveillera l’évènement pendant que celui-ci traverse la structure en arbre.

Routed Events et Composition :

Prenons comme exemple l’évènement Click du Bouton ci-dessus. Lorsque nous cliquons sur l’image qui se trouvent dans cet élément bouton. Comme mentionné ci-dessus, un utilisateur va initier un évènement Click avec un MouseLeftButtonDown event sur certain des éléments enfant dans cette structure en arbre de votre bouton (comme l’élément image dans notre cas du dessus).

Quand le MouseLeftButtonDown évènement se déclenche à partir de l’élément Image, l’évènement PreviewMouseLeftDown commence de l’élément root et se propage jusqu’à l’élément Image. Si personne n’a manipulé cet évènement et a marqué l’évènement comme « handled », un évènement MouseLeftDown  de type « bubble » sera propagé depuis l’élément image jusqu’à l’élément bouton. Le bouton manipule alors cet évènement, marque l’évènement comme handled et propage alors un évènement Click.

Attached Events :

Pour permettre à un élément de manipuler un évènement qui est déclaré dans un élément différent. WPF supporte les Attached Events. Attached Event sont des RoutedEvent qui supporte une déclaration d’un handler dans un autre type que celui où l’évènement est propagé. Par exemple, un élément Grid qui écouterait l’évènement Click de l’élément bouton.

routeevent10

Le code généré par la classe partiel compile-time

 routeevent11

Plus d’information :

Si vous voulez créer vos propre RoutedEvent, je vous invite à lire cet article très intéressant sur les RoutedEvent : http://blogs.developpeur.org/raptorxp/archive/2007/07/18/wpf-comprendre-les-routed-events.aspx

En conclusion :

Vous savez maintenant ce qu’est un RoutedEvent, cette notion est une notion de base de l’environnement WPF et il était un pré requis à connaître avant de rentrer dans les détails du Composite Application Guidance. Si vous avez des questions, des suggestions et/ou des compléments d’information, n’hésitez-pas commenter cet article.

Bon voilà, après quelques années dans le monde de l’ASP.NET, j’ai envie de faire un tour du coté des applications clients de la plateforme .NET. Non pas que je sois blasé par cette technologie mais simplement la curiosité de découvrir un autre monde. Après avoir lu quelques tutoriaux, et vu quelques videos, programmé quelques applications du style Hello World, je me lance dans le vif du sujet. Je tenterai à la manière de Rob Connery d’apprendre et de vous faire apprendre de façon simultanée, ceci, en anglais plus connu sous le nom de “public learning”. J’attendrai donc des retours de votre part via commentaires ou mails (pierre at dervalp.com). Ne soyez pas surpris de trouver des mots non traduit, je ne tenterai pas de traduire certains mots. Je ne suis pas particulièrement un adepte du franglais mais certains mots dans le domaine informatique perdent de leur sens lorsqu’ils sont traduits (le language C# n’est-il lui-même pas écrit en anglais ?).

Revenons à nos moutons, c’est par l’intermédiaire d’une connaissance qui m’a présenté le pattern MVVM que je suis tombé sur une partie très intéressante sur MSDN, le “Composite Application Guidance for WPF and Silverlight” ou sous le nom plus connu de PRISM v2. Ce guide vous permettra de créer des applications qui sont voués à grandir et à supporter les assaults du temps par l’ajout de vue, l’ajout de modules,…

Avant de se lancer dans ce monstre qu’est PRISM v2, je vous invite à vérifier les spécifications systèmes (rien de bien effrayant là dedans) :

  • Microsoft Visual Studio 2008 SP1
  • Microsoft .NET Framework 3.5 SP1 (le .NET Framework 3.5 qui inclu WPF)
  • Microsoft Silverlight (seulement pour les applications Silverlight)
  • Microsoft Silverlight Tools for Visual Studio 2008 SP1 (seulement pour les applications Silverlight)

Pour plus d’info : http://msdn.microsoft.com/en-us/library/dd458809.aspx

Pourquoi utiliser Composite Application Guidance ? Selon Ms, il nous aidera à nous guider dans le but de créer des applications WPF et Silverlight complexes et  flexibles (cela tombe bien, c’est mon but). Des applications “loosely coupled” (cliquez-ici pour la traduction) et dont chaque module peut évoluer de manière indépendante (SoC). En gros, l’application presque parfaite…

Pré-requis :

Afin de bien comprendre tous les concepts présents, il vous faut des connaissances générales en WPF, en Silverlight mais aussi dans ces domaines:

  • le databinding (en gros comment les éléments UI sont reliés aux données dans Silverlight et WPF)
  •  les ressources (data template, control template, style,…)
  • Routed Command (commande routée en français ou comment le client et les entrées de données sont connectées aux contrôles )
  • Routed Events (pour permettre plusieurs “listeners” de recevoir et gérer les êvènements)
  • Users Controls (composants qui permettent de créer des comportements ou des apparences customisées)
  • Dependency Property
  • XAML

Je vous rassure tout de suite, je vous expliquerai un à un ces points lors de différents articles (c’est cela le public learning, on rencontre un concept, on l’explique ;) ).

Quand utiliser Composite Application Guidance ?

Une équipe de développement fait face toujours aux même problèmes au cours d’un projet, le changement de spécification, l’ajout de modules non prévus au départ, nouvelle technologie, mauvais feedback du client,… Tout cela, vous le connaissez aussi bien que moi n’est-ce pas ? C’est pour cela qu’il nous faut être agile ( ;) ), c’est à dire être flexible et pouvoir améliorer son application en continu sans difficulté.  

Ce sont ces défis que Composite Application Guidance tente de relever, enfin rectification, ce sont les developpeurs à l’aide de Composite Application Guidance qui tenteront de relever ces différents défis. Ceci en divisant l’application en des parties peu couplés et semi-indépendantes qui pourront être développées et testées individuellement et ensuite regroupées ensemble dans une application “shell” (coquille en anglais) pour former une solution cohérente et performante. Que de beaux mots, en gros, pour les projets de grande envergures qui sont voués à évoluer au travers le temps.

Exemple d’une application composite (image provenant de MSDN):

dd490815_holsl-fig1en-usmsdn_10

 

 

Composite Application permet de développer, tester et déployer des modules de manière indépendante.

Il fournit également un « shell » commun composé de composant UI construit à partir de modules variés de manière peu couplée. Cela standardise l’apparence et permet d’ajouter des nouvelles fonctionnalités plus facilement.

Il permet la «separation of concerns» pour ce qui du logging et de l’authentification (capacité horizontal) mais également pour ce qui est des fonctionnalités business spécifique à vos applications (capacité vertical).

Il aide à la subdivision d’équipe en spécialisant les développeurs dans sa couche. Ceci permet de bien séparer l’application entre l’interface utilisateur et l’aspect business logic.

Quand ne pas utiliser Composite Application Guidance ?

 Le Composite Application Guidance est déconseillé pour les infrastructures telles que client/serveur, les communications assynchrones et les communications encryptées. Les applications où la performance est la priorité numéro une, les applications d’authenfication et d’authorisation. Il y certainement encore des cas où l’utilisation de Composite Application Guidance ne s’applique pas, nous verrons cela par la suite.

Conclusion :

J’espère vous avoir donné l’envie d’en connaître plus sur cette partie du monde du développement .NET. Je reviendrai très vite avec un prochain article qui vous expliquera les différents requis (databinding, routed command) afin d’être paré lors des explications plus techniques sur le fonctionnement de PRISM.

top