J’ai beau être en vacances au bord de la piscine, quand Microsoft sort une beta du SDK Windows Phone 7, je ne peux pas passer à coté…

J’ai donc pris le temps de travailler un peu sur SL Flow Layouts Library pour inclure le support de cette nouvelle plateforme (j’en ai aussi profité pour y inclure une première version pas encore tout optimisée d’un contrôle Pivot de mon cru) et corriger quelques légers bugs.

Attention par contre, sous WP7, la virtualisation est une fonctionnalité opt-in (car les cas d’utilisation dans lesquels on utilisera un layout type cover-flow ou la virtualisation a un impact négatif sont loin d’être rare).

Comme d’habitude, ça se passe sur CodePlex… Enjoy !


Ça fait un moment que je n’ai pas poste de trucs intéressants sur ce blog. Il faut dire qu’entre le Remix 2010, les divers projets avec Access it et Microsoft, mon temps libre se réduit a peau de chagrin en ce moment…


… surtout qu’il se fait phagocyter par un projet perso que j’entretiens avec ma douce depuis quelques mois : http://www.kaikilia.com. Il s’agit d’une galerie de ses créations photographiques faite entièrement en Silverlight 4 et RIA services, avec un soupçon d’ASP.Net MVC 2 pour SEO (oui, d’ici quelque temps, tout le contenu public du site sera visible via Google et Bing). Je ferai surement des petites vidéos présentant le back-office qui lui aussi est Full Silverlight, avec des outils de cropping, d’édition d’Exif et autres joyeuseries (la grosse complexité du projet réside d’ailleurs dans le backoffice).


N’hésitez pas à commenter le travail de ma belle (qui fait ça en amateur, je précise quand-même), ou à me contacter si vous voulez quelques détails techniques sur SEO, Silverlight, Ria services ou autre !


.Net 4.0 et Silverlight 4 sont sortis en RTM la semaine dernière, et j’ai donc mis à jour le projet et j’en ai profité pour apporter quelques nouveautés au niveau stylisation, layouts, et biensur, une petite dose de bugfixes.

Ca se passe toujours sur codeplex, et n’hésitez pas à faire du Feedback !


Plus tôt dans la journée, j’ai posté à propos d’une technique de PlaneProjection pour WPF à base de Shader Effect. Cette technique avait pour but principal de porter la Silverlight Flow Layouts Library pour WPF. C’est désormais chose faite : le projet CodePlex est mis à jour (binaires + sources), et le projet fait maintenant du Multi-Targeting Silverlight 4.0 RC / WPF 4.0 RC.

 

N’hésitez pas à apporter tout feedback aussi bien sur la librairie en elle-même, que sur la PlaneProjection pour WPF ou les features que vous aimeriez voir.

 

Autre chose, si vous développez vos propres algorithmes de layout, n’hésitez pas à me contacter via ce blog (ou via le site codeplex), pour venir agrémenter la future bibliothèque d’algorithmes qui va bientôt venir…


Depuis la version 3, Silverlight propose une fonctionnalité permettant de donner un effet de perspective à nos UIElements de manière très simple et très efficace : les Plane Projections. On profite ainsi d’un affichage en perspective 3D très simple à mettre en place et très performant.

 

Le problème

 

WPF ne fournit pas de Plane Projections, et nous oblige à passer par de la « vraie » 3D dès lors que l’on veut afficher quelque chose en perspective. Cela pose 2 problèmes importants :

  • la complexité requise lorsque l’on veut simplement afficher une surface plane en perspective
  • les performances qui chutent dramatiquement quand on multiplie le nombre de Viewport2DVisual3D

 

En effet, avec WPF, appliquer un effet de perspective à un élément requiert les étapes suivantes :

  • Créer un Viewport3D
  • Lui associer une PerspectiveCamera
  • Lui ajouter un Viewport2DVisual3D
  • Lui affecter un modèle (avec les coordonnées de textures et les normales)
  • Lui affecter la transformation3D correcte

 

Cela fait beaucoup d’étapes et certaines ne sont pas forcément simple à comprendre lorsque l’on travaille essentiellement dans un monde 2D.

 

Au niveau des performances, outre les nombreux objets nécessaires et couteux mis en œuvre, il faut savoir que pour chaque transition entre une surface 2D et un Viewport3D, WPF produit une Render Target Direct3D intermédiaire avec des conséquences très importantes pour les performances. en effet chaque RenderTarget consomme une quantité importante de mémoire vidéo, d’autant que sous Vista / 7, l’anti-aliasing 4x est appliqué à chaque RenderTarget participant à WPF 3D, et le switch de RenderTarget est quelque chose de très couteux. Il suffit de créer une scène avec une 15aine de Viewport2DVisual3D pour se rendre compte de l’impact.

 

Solution envisagée

 

Pour pallier à ces 2 problèmes (et aussi pour pouvoir porter la Flow Layout Library pour WPF), j’ai décidé de tenter une approche différente, et très proche de ce qui semble avoir été fait pour Silverlight. Il s’agit de générer l’effet de perspective à partir d’un ShaderEffect combiné à un TranslateTransform pour reproduire l’effet d’une PlaneProjection. Comment cela est-il possible ? Simplement avec un petit peu de mathématiques (au passage, pour les poilus, le livre Mathematics for 3D Game Programming & Computer Graphics, c’est top).

 

On commence par produire côté C# une matrice de transformation 3D (composée de la matrice de transformation par rapport à la position d’origine, de la matrice de transformation par rapport au point de vue, et de la matrice de projection qui donne l’effet de perspective)  et d’en déduire l’équation du plan généré (je vous passe la formule mathématique, ça parle de multiplication matricielles, de produits scalaires et autres joyeusetés). Cela n’a besoin d’être fait que lorsque la transformation demandée change.

 

 

Une fois qu’on obtient cette équation (composée de la normale au plan et de la distance minimale entre le point {0,0,0} et le plan), on la passe au Pixel Shader avec la matrice inverse de celle utilisée pour transformer le plan. Dans le PixelShader, pour chaque pixel à rendre, on va calculer l’intersection entre le rayon partant de ce point et se projetant dans l’axe Z, et le plan (définit par l’équation produite à l’étape précédante). On multiplie alors cette coordonnée par la matrice de transformation inverse pour savoir quelle est la position au sein du plan (et donc obtenir la coordonnée du Pixel de la texture d’origine à renvoyer).

 

On ajoute à ça quelques petites optimisations du genre clipping de la zone de rendu et utilisation d’un TranslateTransform pour éviter d’avoir à appliquer cet effet sur une surface trop grande (dans le cas où la PlaneProjection produit une translation importante) et la création d’un GeneralTransform utilisé pour le HitTesting,  et on se retrouve avec une solution beaucoup plus simple à utiliser (au final, on obtient la même chose que la PlaneProjection de Silverlight) et beaucoup plus performante (pas de RenderTarget intermédiaire, consommation de mémoire vidéo réduite…) que le Viewport2DVisual3D. Bien sûr l’inconvénient est que l’on ne peut pas mapper nos surfaces 2D sur des objets 3D autres que des plans avec cette technique, mais dans de nombreux cas, c’est exactement ce à quoi l’on veut se limiter !
(note, je ne ferai pas de listing de code dans ce post, car c’est long et pas vraiment très expressif, mais vous pourrez le télécharger à la fin de l’article).

 

Le résultat

 

Au final on va pouvoir créer ce genre d’effet :

Avec très peu d’efforts :

 

<Border Background="Transparent"  x:Name="border">

   <Media:PlaneProjection.PlaneProjection>

      <Media:PlaneProjection/>

   </Media:PlaneProjection.PlaneProjection>


</Border>
   <StackPanel Grid.Column="1">

      <TextBlock Text="GlobalOffsetX" />

      <Slider x:Name="offsetX" Minimum="-200" Maximum="200"

              Value="{Binding ElementName=border, Mode=TwoWay, Path=(Media:PlaneProjection.PlaneProjection).GlobalOffsetX}" />

      <TextBlock Text="GlobalOffsetY" />

      <Slider x:Name="offsetY" Minimum="-200" Maximum="200"

              Value="{Binding ElementName=border, Mode=TwoWay, Path=(Media:PlaneProjection.PlaneProjection).GlobalOffsetY}" />

      <TextBlock Text="GlobalOffsetZ" />

      <Slider x:Name="offsetZ" Minimum="-200" Maximum="200" 

              Value="{Binding ElementName=border, Mode=TwoWay, Path=(Media:PlaneProjection.PlaneProjection).GlobalOffsetZ}" />

      <TextBlock Text="RotationX" />

      <Slider x:Name="rotationX" Minimum="-180" Maximum="180"

              Value="{Binding ElementName=border, Mode=TwoWay, Path=(Media:PlaneProjection.PlaneProjection).RotationX}" />

      <TextBlock Text="RotationY" />

      <Slider x:Name="rotationY" Minimum="-180" Maximum="180"

              Value="{Binding ElementName=border, Mode=TwoWay, Path=(Media:PlaneProjection.PlaneProjection).RotationY}" />

      <TextBlock Text="RotationZ" />

      <Slider x:Name="rotationZ" Minimum="-180" Maximum="180"

              Value="{Binding ElementName=border, Mode=TwoWay, Path=(Media:PlaneProjection.PlaneProjection).RotationZ}" />

</StackPanel>

 

Ça se présente juste sous la forme d’une AttachedProperty, et au niveau utilisation, c’est la seule différence avec la PlaneProjection de Silverlight.

Bien sûr, on va aussi pouvoir faire des choses plus complexes… comme le portage de Silverlight Flow Layout Library par exemple qui va venir avec la sortie de Silverlight 4 RC :

Les sources :

 

Vous pourrez retrouver les sources dans le projet CodePlex http://slflow.codeplex.com lors de la prochaine release. En attendant je les mets a dispo ici meme.


As this post is about a scenario that is not discussed very much even in English, I won’t write this post in French in order to have a broader audience.

WPF and Silverlight are very good candidates for applying IoC concepts. Coupled with MVVM pattern, IoC make it really easier to build testable and robust applications. However, one limitation is that the Xaml language itself does not play well with it (as it’s basically an object graph Serialization / Deserialization language and so it only works with concrete types). So to instantiate data contexts from an IoC container, we need to write code-behind code. This problem is even more annoying for the WF use of Xaml (as with WF4.0, we do not have Code-Behind anymore).

Fortunately, with .Net 4.0, the xaml readers and writers have been completely refactored in a very extensible way. So we are able to provide our own XamlSchemaContext that provides the XamlNodes instantiation logic. The resolution of a type in the .net 4.0 Xaml reader is done through an abstraction layer:

From a given xaml namespace / xaml element name, the XamlSchemaContext is responsible of resolving a XamlType which represents a Clr Type. This XamlType provide a TypeInvoker responsible of the instantiation of a XamlType. By creating a custom XamlSchemaContext that replace the default XamlType resolution by a unity-enabled XamlType / XamlTypeInvoker whenever it finds that the default one is not capable of creating the requested object, we can rely on the container to resolve these types.

So we’ll be able to parse things like that:

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

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

    xmlns:my="clr-namespace:XamlIoCDemo;assembly=XamlIoCDemo" >

    <StackPanel>

        <ContentControl x:Name="barContent">

            <my:IBar />

        </ContentControl>

        <ContentControl Content="{Binding Content.OtherService, ElementName=barContent}" />

    </StackPanel>

</Window>

 

With IBar being an interface. I won’t go trough the details of the implementation, but here is what I wrote to parse this Xaml and display it :

IUnityContainer container = new UnityContainer();

container.RegisterType<IBar, BarImpl>();

container.RegisterType<IOtherService, OtherServiceImpl>();

 

var ctx = new WpfUnityEnabledXamlSchemaContext(container);

 

var reader = new XamlXmlReader("SampleWindow.xaml",ctx);

var result = System.Windows.Markup.XamlReader.Load(reader) as Window;

result.ShowDialog();

You can see that I wrote a WPF-specific xaml schema context (which is needed for the Wpf-specific features, like binding expressions). I also provided a more generic one for general purpose Xaml. I did not check it against WF 4.0, but I’ll try it in my way back from the MVP summit.

Here is the source code for all of that:

http://www.simonferquel.net/blog/XamlIOC.zip

 

 

Special thanks to Rob Relyea who made great demos about Xaml 2009 this week at the MVP Global Summit


De lundi à mercredi prochain auront lieu les Techdays 2010 à Paris, l’évènement Microsoft France de l’année. J’aurai le plaisir d’y co-animer 3 sessions :

  • Model-View-ViewModel et testabilité pour WPF et Silverlight
    Lundi de 13h à 14h en compagnie de Richard Clark.

Cette session sera réalisée en WPF, mais tout ce que l’on va montrer reste valable avec Silverlight. Au niveau testabilite / isolation de composant, on abordera des cas typiques : Tests de composants asynchrones, isolation de la couche ViewModel par rapport à la couche Service, injection de dépendances…

  • Développement Microsoft Surface
    Lundi de 14h30 à 15h30 en compagnie de Cyril Giacopino

Cette session couvrira le SDK Surface 1.0 SP1, et présentera les diverses fonctionnalité au travers d’une application développée au sein d’Access it par Julien Corioland, moi-meme, et le résultat de la réflection de toute l’équipe parisienne autour de scénarios collaboratifs avec Surface et Team Foundation Server (et la participation d’Aude Mousset pour que ce soit un minimum joli…)

  • Workshop – Développement parallèle
    Mardi de 17h30 à 18h30 avec Patrice Lamarche

Une session dédiée aux nouveautés du Framework .Net 4.0 en terme de multi-threading, où vous pourrez vous essayer au différentes formes que peut prendre la parallélisation : Data Parallelism avec PLinq, Task Parallelism avec TPL, et pipelines d’agents avec la communication par messages… Une session très interactive, avec en cadeau des démo Bonux des nouveautés des outils de debug de VS 2010, et d’un outil de détection de Dead Lock sorti des labo de Microsoft Research : Chess.

 

Cette année, rassurez vous, je ne ferai pas de démo sous SOS devant un amphi de 400 personnes… C’est que des sessions avec des trucs faciles dedans !


Je viens de mettre à jour le projet CodePlex avec les dernières sources, et j’en ai profité pour en faire une Release publique.

Cette version inclue la manipulation par gestures et un moteur d’inertie, en plus des fonctionnalités présentées précédement, et de quelques BugFixes.

J’en ai bien sur aussi profité pour mettre à jour le Showroom.

 

A venir :

  • Une librairie d’algorithmes de layouts
  • Un portage WPF
  • Un portage Surface

 

Comme d’habitude, tout Feedback est le bienvenu !


Hier soir, en compagnie de Julien Corioland, j’ai animé un Live Meeting à propos de MEF (vous pouvez d’ailleurs le regarder / télécharger à cette adresse).

Comme promis, voici donc le code source de mes démos (allez voir le blog de Julien pour retrouver les siennes) : www.simonferquel.net/blog/5-AdminMenu.rar


Un des types de layouts particulièrement en vogue dans les applications RIA est le Coverflow (le nom provient d'un mode de navigation introduit par Apple dans iTunes, iPod et iPhone).

 

Depuis la sortie de Silverlight, de nombreux contrôles ont été publiés par la communauté mais aucun n'est parfait pour le moment à mes yeux. Après un peu de réflexion j'en suis donc venu à m'établir une Feature-list et de lancer un projet CodePlex. Les fonctionnalités que je souhaite implémenter sont les suivantes :

 

  • Scalabilité : le contrôle doit pouvoir contenir des milliers d’éléments sans broncher. Pour ceci je compte mettre en place de la Virtualisation de conteneurs
  • Data-Binding : le contrôle doit être un ItemsControl, accepter une ItemsSource et un ItemTemplate, et supporter le Binding TwoWay sur ses SelectedIndex et SelectedItem
  • Styling/Templating : Le contrôle doit être aisément personnalisable, exposer des VisualStates et fournir une expérience Design Time parfaite. De plus, il doit fournir un moyen à son ItemTemplate de connaitre l’état de sélection de l’élément courant
  • Extensible : Je n’ai jamais vu 2 projets ou le client voulait exactement le même algorithme de layout : plus ou moins d’éléments visibles, rotation des éléments différente, effet de perspective ou à plat… Le meilleur moyen de proposer quelque chose qui s’adapte vraiment à chaque cas, est d’externaliser la logique de layout et de proposer au développeur l’utilisant de fournir sa propre implémentation sans avoir à implémenter toutes les taches annexes (entrées utilisateur, logique de sélection, virtualisation…)
  • Expérience “Out of the Box” (sans style / layout particulier) suffisante pour prototyper des applications qui en jettent
  • Modèle de manipulations riche (sélection par clic, au clavier, par “panning”, touch…). Fournir une API de manipulation extensible (yet to be designed pour le moment, mais j’ai quelques idées a ce sujet)

Mes plans sont d’avoir une version stabilisée d’ici la RC de Silverlight 4 avec toutes les fonctionnalités décrites ci-dessus, en License MS-PL.

 

D’ici-là, je laisserai à disposition une page de demo régulièrement mise à jour avec les nouveautés apportées. Un projet Codeplex est aussi en préparation, je pousserai les sources dessus après avoir peaufine 2-3 choses…

 

image

 

image

 

Bien entendu, tout feedback sur le look-and-feel et proposition de fonctionnalité est fortement encouragé…

 

 

Simon

 

 

Update : Le projet est Codeplexifié à l’adresse suivante : http://slflow.codeplex.com/. La qualité du code est pas encore clean, ca nécessite un peu de refactoring, de testing et de doc pour attendre un niveau de qualité acceptable, mais vous pouvez commencer à jouer avec et à faire du Feedback :-).