<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
    <channel>
        <title>SimonFerquel.net</title>
        <link>http://www.simonferquel.net//blog/Default.aspx</link>
        <description>A blog about .Net development</description>
        <language>fr-FR</language>
        <copyright>Simon FERQUEL</copyright>
        <managingEditor>simon.ferquel@hotmail.fr</managingEditor>
        <generator>Subtext Version 1.9.5.176</generator>
        <image>
            <title>SimonFerquel.net</title>
            <url>http://www.simonferquel.net//blog/images/RSS2Image.gif</url>
            <link>http://www.simonferquel.net//blog/Default.aspx</link>
            <width>77</width>
            <height>60</height>
        </image>
        <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/Simonferquelnet" type="application/rss+xml" /><item>
            <title>[.Net 4.0] Parallel Task Library</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/01H-tk1OgIM/.net-4.0-parallel-task-library.aspx</link>
            <description>&lt;p&gt;La beta 1 de Visual Studio 2010 et du Framework .Net 4.0 est disponible depuis quelques jours (normalement, si vous lisez ce blog, vous êtes déjà au courrant !), et une des nouveautés majeures de cette nouvelle version (si ce n’est LA nouveauté) concerne le Multi-Threading. En effet, .Net 4.0 intègre un certain nombre d’améliorations au niveau du ThreadPool qui ont permis de créer tout un jeu d’APIs dédiées à l’exécution de tâches en parrallèle et à leur synchronisation.&lt;/p&gt;  &lt;p&gt;Ces APIs se distinguent en 3 catégories :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Task &amp;amp; TaskScheduler : Il s’agit de la possibilité de créer des tâches avec une granularité très fine, de définir des dépendances (telle tâche ne peut démarrer avant la fin de l’exécution de telle autre), et de les exécuter. Le TaskScheduler se chargera alors de distribuer ces tâches entre les différents Threads du ThreadPool pour exploiter au mieux les ressources de la machine. On peut aussi utiliser les tâches pour effectuer des traitements asynchrones afin de ne pas bloquer un Thread de rendu en WPF ou Windows Forms par exemple. &lt;/li&gt;    &lt;li&gt;Parallel loops : Il s’agit d’un ensemble de méthodes statiques remplacant les boucles traditionelles, permettant de traiter chaque itération d’une boucle for / foreach dans des tâches séparées afin de parallèliser le traitement, et potentiellement d’aggréger les résultats des traitements de chaque tour de boucle. Parallel.For, Parallel.Foreach, Parallel.Do etc. reposent sur les classes Task et TaskScheduler. &lt;/li&gt;    &lt;li&gt;Parallel Linq : Il s’agit d’une extension à Linq to Objects permettant de paralleliser le traitement d’une requête. Si vous aimé tout comme moi le style de développement fonctionnel apporté par C# 3.0 et que vous mettez des lambdas, et des appels à Enumerable.Where, Enumerable.Select, etc. partout dans votre code, vous adorerez PLinq :). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;L’exemple qui vient avec cet article exploite essentiellement les parallel loops. Le but de l’application est d’effectuer des traitements sur une série d’images (ajustement de contraste). L’algorythme employé n’est pas le plus optimisé qui soit, le but étant de mettre en valeur la simplicité des APIs plutôt que de concurrencer Photoshop. L’exemple a aussi l’avantage de montrer quelques astuces spécifiques au développement multi-thread avec WPF.&lt;/p&gt;  &lt;h2&gt;Focus 1 : chargement des images&lt;/h2&gt;  &lt;p&gt;La première utilisation que je fais de PTL, est assez classique, et équivaut à l’utilisation d’un BackgroundWorker. Il s’agit simplement de charger les images dans un thread séparé pour éviter de bloquer le thread UI de WPF :&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(ofd.ShowDialog() ?? &lt;span style="color: blue"&gt;false&lt;/span&gt;)
{
    _images.Clear();
    &lt;span style="color: #2b91af"&gt;Task&lt;/span&gt;.Factory.StartNew(() =&amp;gt;
        {
            &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;file &lt;span style="color: blue"&gt;in &lt;/span&gt;ofd.FileNames)
            {
                &lt;span style="color: blue"&gt;try
                &lt;/span&gt;{
                    &lt;span style="color: blue"&gt;var &lt;/span&gt;source = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;BitmapImage&lt;/span&gt;(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Uri&lt;/span&gt;(file));
                    source.Freeze();
                    &lt;span style="color: blue"&gt;var &lt;/span&gt;tuple = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SourceAndTarget &lt;/span&gt;{ Source = source };
                    Dispatcher.BeginInvoke((&lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;)(() =&amp;gt;
                        {
                            _images.Add(tuple);
                            tuple.Target = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WriteableBitmap&lt;/span&gt;(source);
                        }));
                }
                &lt;span style="color: blue"&gt;catch
                &lt;/span&gt;{
                    &lt;span style="color: #2b91af"&gt;MessageBox&lt;/span&gt;.Show(&lt;span style="color: #a31515"&gt;"Image " &lt;/span&gt;+ file + &lt;span style="color: #a31515"&gt;" failed"&lt;/span&gt;);
                }
            }
        }).ContinueWith((t) =&amp;gt;
            Dispatcher.BeginInvoke((&lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;)(() =&amp;gt; LoadingImages = &lt;span style="color: blue"&gt;false&lt;/span&gt;)));
}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Task.Factory.StartNew permet de créer une tâche à partir d’un délégué (ici une lambda) et de la scheduler. Notez la ligne source.Freeze(), elle est très importantes. En effet, avec WPF, tout DependencyObject ne peut par défaut être manipulé que dans le thread où il a été créé. Hors, comme on est dans un thread différent du Thread UI, la BitmapImage que l’on vient de créer ne peut pas, par défaut être accessible par le Thread UI. &lt;/p&gt;

&lt;p&gt;Il existe dans WPF une classe dérivant de DependencyObject appelée Freezable permettant de “figer” l’objet et le rendre immutable. Une fois que l’objet est figé, il n’y a plus de risques liés à la concurrence d’accès (car tout accès en écriture aux propriétés est désactivé), l’objet devient accessible depuis n’importe quel thread. Beaucoup d’objets (notament les images, les brushes, les Paths etc) de WPF héritent de cette classe Freezable. Une fois notre BitmapImage crée, nous appelons donc sa méthode Freeze() pour la rendre accessible au thread UI de WPF.&lt;/p&gt;

&lt;p&gt;Le cas de la WriteableBitmap est plus complexe, car elle demande d’être accessible par le thread UI tout en restant modifiable. Grace au Dispatcher, nous basculons donc dans le Thread UI et créons la WriteableBitmap depuis celui-ci.&lt;/p&gt;

&lt;h2&gt;Focus 2 : traitement en parallèle avec Parallel.For&lt;/h2&gt;

&lt;p&gt;Le traitement d’image se prête assez facilement à la parallèlisation. En effet, il suffit de découper l’image source, calculer les différentes portions dans des threads séparés et recomposer l’image destination. La classe ImageProcessor fournie dans l’exemple illustre cela parfaitement : que l’on passe en parallèle ou que l’on reste en traitement séquenciel, la grosse majorité du code reste identique. Seulement dans un cas, on parallèlise la boucle de traitement : &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;ProcessSequential(&lt;span style="color: #2b91af"&gt;WriteableBitmap &lt;/span&gt;target, &lt;span style="color: #2b91af"&gt;ITransformer &lt;/span&gt;transformation)
{
    &lt;span style="color: #2b91af"&gt;Contract&lt;/span&gt;.Requires(target != &lt;span style="color: blue"&gt;null&lt;/span&gt;);
    &lt;span style="color: #2b91af"&gt;Contract&lt;/span&gt;.Requires(transformation != &lt;span style="color: blue"&gt;null&lt;/span&gt;);
    &lt;span style="color: blue"&gt;int &lt;/span&gt;count = &lt;span style="color: #2b91af"&gt;Math&lt;/span&gt;.Min(&lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.ProcessorCount * 2, _image.PixelWidth);
    &lt;span style="color: blue"&gt;int &lt;/span&gt;chunkWidth = _image.PixelWidth / count;

    &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; i &amp;lt; count; i++)
    {
        ProcessChunck(target, transformation, count, chunkWidth, i);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;ProcessParallel(&lt;span style="color: #2b91af"&gt;WriteableBitmap &lt;/span&gt;target, &lt;span style="color: #2b91af"&gt;ITransformer &lt;/span&gt;transformation)
{
    &lt;span style="color: #2b91af"&gt;Contract&lt;/span&gt;.Requires(target != &lt;span style="color: blue"&gt;null&lt;/span&gt;);
    &lt;span style="color: #2b91af"&gt;Contract&lt;/span&gt;.Requires(transformation != &lt;span style="color: blue"&gt;null&lt;/span&gt;);
    &lt;span style="color: blue"&gt;int &lt;/span&gt;count = &lt;span style="color: #2b91af"&gt;Math&lt;/span&gt;.Min(&lt;span style="color: #2b91af"&gt;Environment&lt;/span&gt;.ProcessorCount * 2, _image.PixelWidth);
    &lt;span style="color: blue"&gt;int &lt;/span&gt;chunkWidth = _image.PixelWidth / count;

    &lt;span style="color: #2b91af"&gt;Parallel&lt;/span&gt;.For(0, count, (i) =&amp;gt;
    {
        ProcessChunck(target, transformation, count, chunkWidth, i);
    });
    
}&lt;/pre&gt;

&lt;p&gt;Le nombre de “morceaux” d’image générés est lié au nombre de processeurs. Le *2 est simplement là pour augmenter la granularité car on ne sait pas si l’algorythme de transformation prendra autant de temps pour chaque morceau d’image. Le contenu de la méthode ProcessChunk n’est quand à lui pas très compliqué. Il s’agit simplement de récupérer les données de l’image source correspondant au morceau à traiter, de le traiter, et de l’injecter dans la WritableBitmap. On aura d’ailleurs besoin de se replacer dans le Thread UI pour effectuer cette dernière opération (la seule à ne pas être parallèlisée) : &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;ProcessChunck(&lt;span style="color: #2b91af"&gt;WriteableBitmap &lt;/span&gt;target, &lt;span style="color: #2b91af"&gt;ITransformer &lt;/span&gt;transformation, &lt;span style="color: blue"&gt;int &lt;/span&gt;count, &lt;span style="color: blue"&gt;int &lt;/span&gt;chunkWidth, &lt;span style="color: blue"&gt;int &lt;/span&gt;i)
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;width = chunkWidth;
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(i == count - 1)
        width += _image.PixelWidth % chunkWidth;

    &lt;span style="color: blue"&gt;var &lt;/span&gt;rect = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Int32Rect&lt;/span&gt;(i * chunkWidth, 0, width, _image.PixelHeight);
    &lt;span style="color: blue"&gt;int &lt;/span&gt;stride = width * 4;
    &lt;span style="color: blue"&gt;byte&lt;/span&gt;[] data = &lt;span style="color: blue"&gt;new byte&lt;/span&gt;[stride * _image.PixelHeight];
    _image.CopyPixels(rect, data, stride, 0);
    &lt;span style="color: blue"&gt;var &lt;/span&gt;transformed = transformation.Transform(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ImageChunk&lt;/span&gt;(rect, data));
    target.Dispatcher.BeginInvoke((&lt;span style="color: #2b91af"&gt;Action&lt;/span&gt;)(() =&amp;gt;
    {
        target.WritePixels(transformed.Rect, transformed.Data, stride, 0);
    }));
}&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Parallel Task Library apporte une réelle facilité de syntaxe pour le développement d’applications faisant appel au parallèlisme (que ce soit pour effectuer un traitement asynchrone ou pour exploiter la puissance d’un processeur multi-coeur). En plus de cela, Visual Studio 2010 apporte une collection d’outils permettant de faciliter le Debugging d’applications multi-thread, ainsi qu’un outil de profiling permettant de détecter les problèmes rencontrés dans ces applications (contentions, attente sur une ressource partagées…).&lt;/p&gt;

&lt;p&gt;Ce qu’il ne faut par contre pas oublier, c’est que quelque soit la technologie employée (PTL, OpenMP, etc…), il ne s’agit que d’outils simplifiant les aspects technique de la création d’applications Multi-Thread. En effet, PTL ne dispense pas le développeur de “penser” ses algorythmes dans un style parallèle (découpage en tâches, détection des tâches non-dépendantes, utilisation d’objets immutables, éviter les partages d’états…). Il faudra donc de toute façon se méfier des Race conditions, des deadlocks, etc. Le style de programmation fonctionnel apporté par C# 3.0 se prète par contre très bien à la parallèlisation, car il pousse à l’utilisation d’objets immutables et donc évite le problème le plus courrant lors du développement parallèle : le partage d’état.&lt;/p&gt;

&lt;p&gt;Sources de la solution : &lt;a href="http://www.simonferquel.net/blog/PfxSample.zip"&gt;ici&lt;/a&gt;.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9e23f023-b1a4-44cc-b84e-7d3f953313d0" class="wlWriterEditableSmartContent"&gt;Mots clés Technorati : &lt;a href="http://technorati.com/tags/.Net+4.0" rel="tag"&gt;.Net 4.0&lt;/a&gt;,&lt;a href="http://technorati.com/tags/WPF" rel="tag"&gt;WPF&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Parallel" rel="tag"&gt;Parallel&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/50.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=01H-tk1OgIM:yQrYZK2hk00:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=01H-tk1OgIM:yQrYZK2hk00:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=01H-tk1OgIM:yQrYZK2hk00:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=01H-tk1OgIM:yQrYZK2hk00:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=01H-tk1OgIM:yQrYZK2hk00:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=01H-tk1OgIM:yQrYZK2hk00:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/01H-tk1OgIM" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/06/02/.net-4.0-parallel-task-library.aspx</guid>
            <pubDate>Tue, 02 Jun 2009 08:18:38 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/50.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/06/02/.net-4.0-parallel-task-library.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/50.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/50.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/06/02/.net-4.0-parallel-task-library.aspx</feedburner:origLink></item>
        <item>
            <title>[Silverlight 3] Paging with RIA controls + M-V-VM without DomainDataSource</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/YnsDyjvA9MY/silverlight-3-paging-with-ria-controls--m-v-vm-without-domaindatasource.aspx</link>
            <description>&lt;p&gt;I think this topic is quite important and quite unanswered even on English-speaking blogs, so I decided to publish this entry in english… sorry French frogs!&lt;/p&gt;  &lt;p&gt;So, a couple of weeks ago, &lt;a href="http://www.nikhilk.net"&gt;Nikhil Kothari&lt;/a&gt; has written a very &lt;a href="http://www.nikhilk.net/NET-RIA-Services-ViewModel-Pattern.aspx"&gt;interesting blog&lt;/a&gt; post about encapsulating a RIA Services DomainContext into a ViewModel. The only feature that were not covered by the blog post was server-side paging and sorting without exposing the DomainContext and without using a DomainDataSource.&lt;/p&gt;  &lt;p&gt;DomainDataSource is a control that encapsulate a DomainContext to provide an ICollectionView and IPagedCollectionView implementation which will be used by the RIA controls (DataGrid, DataPager…). This implementation does trigger a roundtrip to the server when the user ask for a sort or paging operation (using DataGrid headers, or DataPager control).&lt;/p&gt;  &lt;p&gt;In a comment of his blog, Nikhil exposed a very interesting idea to make server-side paging / sorting work with a ViewModel : Implement a control similar to the DomainDataSource, but encapsulating a custom ViewModel. I have been thinking about this for a couple of days, and I implemented something that does that using reflection. &lt;/p&gt;  &lt;p&gt;Here is the usage :&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;SStuff_Ria&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;PagingObjectProvider &lt;/span&gt;&lt;span style="color: red"&gt;x&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: red"&gt;Name&lt;/span&gt;&lt;span style="color: blue"&gt;="pagingObjectProvider" 
                                 &lt;/span&gt;&lt;span style="color: red"&gt;DataSource&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;Mode&lt;/span&gt;&lt;span style="color: blue"&gt;=OneWay}" 
                                 &lt;/span&gt;&lt;span style="color: red"&gt;GoToPageMethodName&lt;/span&gt;&lt;span style="color: blue"&gt;="LoadProductsPage" 
                                 &lt;/span&gt;&lt;span style="color: red"&gt;ItemsSourcePropertyName&lt;/span&gt;&lt;span style="color: blue"&gt;="Products" 
                                 &lt;/span&gt;&lt;span style="color: red"&gt;PageChangingPropertyName&lt;/span&gt;&lt;span style="color: blue"&gt;="PageChanging" 
                                 &lt;/span&gt;&lt;span style="color: red"&gt;PageIndexPropertyName&lt;/span&gt;&lt;span style="color: blue"&gt;="PageIndex" 
                                 &lt;/span&gt;&lt;span style="color: red"&gt;TotalItemCountPropertyName&lt;/span&gt;&lt;span style="color: blue"&gt;="TotalItemCount" /&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;font color="#0000ff" face="Courier New"&gt;&lt;/font&gt;

&lt;p&gt;(of course, the DataContext is an instance of my ViewModel, which exposes the specified methods and properties, and implements INotifyPropertyChanged).&lt;/p&gt;

&lt;p&gt;After that, we can reference this DataSource as we did with the DomainDataSource:&lt;/p&gt;

&lt;p&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;data&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataGrid &lt;/span&gt;&lt;span style="color: red"&gt;Grid.Row&lt;/span&gt;&lt;span style="color: blue"&gt;="1" 
    &lt;br /&gt;              &lt;/span&gt;&lt;span style="color: red"&gt;IsReadOnly&lt;/span&gt;&lt;span style="color: blue"&gt;="True" 
    &lt;br /&gt;              &lt;/span&gt;&lt;span style="color: red"&gt;ItemsSource&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;ElementName&lt;/span&gt;&lt;span style="color: blue"&gt;=pagingObjectProvider,&lt;/span&gt;&lt;span style="color: red"&gt;Path&lt;/span&gt;&lt;span style="color: blue"&gt;=Data}" 
    &lt;br /&gt;              &lt;/span&gt;&lt;span style="color: red"&gt;AutoGenerateColumns&lt;/span&gt;&lt;span style="color: blue"&gt;="False"&amp;gt; 
    &lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;data&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataGrid.Columns&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt; 
    &lt;br /&gt;        … 

    &lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;data&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataGrid.Columns&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt; 
    &lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;data&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataGrid&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;dataControls&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataPager &lt;/span&gt;&lt;span style="color: red"&gt;Grid.Row&lt;/span&gt;&lt;span style="color: blue"&gt;="2" 
                        &lt;/span&gt;&lt;span style="color: red"&gt;Source&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;ElementName&lt;/span&gt;&lt;span style="color: blue"&gt;=pagingObjectProvider, &lt;/span&gt;&lt;span style="color: red"&gt;Path&lt;/span&gt;&lt;span style="color: blue"&gt;=Data}"/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;One really cool side effect, is that the PagingObjectProvider does not depends on RIA Services at all and could be used with custom WCF Services or with ADO.Net Data Service. So we will be able to use it as soon as SL3 is out (no need to wait for a RIA Services RTW).&lt;/p&gt;

&lt;p&gt;Here are the sources (with 2 samples : One with RIA Services and one with custom WCF Service) : &lt;a href="http://www.simonferquel.net/blog/SStuff.RIA.zip"&gt;SStuff.RIA.zip&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/49.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=YnsDyjvA9MY:sS4-8HhaGIU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=YnsDyjvA9MY:sS4-8HhaGIU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=YnsDyjvA9MY:sS4-8HhaGIU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=YnsDyjvA9MY:sS4-8HhaGIU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=YnsDyjvA9MY:sS4-8HhaGIU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/YnsDyjvA9MY" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/05/12/silverlight-3-paging-with-ria-controls--m-v-vm-without-domaindatasource.aspx</guid>
            <pubDate>Tue, 12 May 2009 17:02:57 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/49.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/05/12/silverlight-3-paging-with-ria-controls--m-v-vm-without-domaindatasource.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/49.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/49.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/05/12/silverlight-3-paging-with-ria-controls--m-v-vm-without-domaindatasource.aspx</feedburner:origLink></item>
        <item>
            <title>[Silverlight] Silverlight 3 + RIA Services + MVVM et testabilit&amp;eacute;</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/Bl7zG41NP98/silverlight-silverlight-3--ria-services--mvvm-et-testabiliteacute.aspx</link>
            <description>&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id="scid:F60BB8FA-6F02-4999-8F5E-9DD4E92C4DA7:dd5c3bee-ef22-489a-b0b9-f575f0aecf3b" class="wlWriterEditableSmartContent"&gt;
&lt;div&gt;&lt;a target="_self" href="http://simonferquel.net/blog/images/simonferquel_net/blog/WindowsLiveWriter/SilverlightSilverlight3RIAServicesMVVMet_F519/solution.zip"&gt;Téléchargez la solution&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Microsoft a récemment publié la Beta 1 de Silverlight 3 ainsi qu’une CTP des .Net RIA Services. Je commencerai d’ailleurs par rappeler que si Silverlight 3 RTW est prévu pour l’été prochain, les RIA Services n’ont pour l’instant aucune date de sortie, et sont sujet à des Breaking Changes TRES conséquents (les plans sont d’en faire une sorte d’extension à ADO.Net Data Services).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Toujours est-il que le modèle est très intéressant et que dès aujourd’hui, nous pouvons commencer à travailler sur l’intégration du DomainContext ainsi que des nouveautés propre à Silverlight 3 avec les Design Pattern existants actuellement pour la création d’application LOB (Line of business) avec Silverlight. Aujourd’hui je vais donc présenter quelques  “early”-astuces avec Silverlight 3, RIA Services, Unity Application bloc et le pattern MVVM.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;L’application présentée est très simple : Il s’agit simplement d’une grille de données affichant une liste de personnes avec leur manager avec pour chaque ligne un bouton “Foo”, qui lorsqu’il est cliqué fait apparaitre une MessageBox contenant le nom de la personne :&lt;/p&gt;
&lt;p&gt;&lt;a href="http://simonferquel.net/blog/images/simonferquel_net/blog/WindowsLiveWriter/SilverlightSilverlight3RIAServicesMVVMet_F519/image_2.png"&gt;&lt;img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title="image" border="0" alt="image" width="503" height="484" src="http://simonferquel.net/blog/images/simonferquel_net/blog/WindowsLiveWriter/SilverlightSilverlight3RIAServicesMVVMet_F519/image_thumb.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Les données sont exposées par le serveur via RIA Services. Pour des raisons de simplicité, il n’y a pas de base de donnée, seulement quelques instances en mémoire.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Afin de pouvoir utiliser le pattern MVVM, il m’a aussi fallu implémenter l’interface ICommand ainsi que créer un modèle d’adapters capable d’associer une commande à un contrôle. Je ne détaillerai pas ce code, car il n’est pas du tout spécifique à Silverlight 3, et si vous travaillez en mode MVVM avec Silverlight, vous avez déjà très certainement ce qu’il vous faut pour associer des commandes à des boutons de manière déclarative.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt; &lt;/h2&gt;
&lt;h2&gt;Rappel sur M-V-VM&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;M-V-VM représente un modèle à 3 responsabilités :&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Le modèle : Il s’agit de la business logique de l’application cliente, qui doit être indépendante de la technologie d’affichage. En général dans une application Silverlight, il s’agit de business entities échangées avec le serveur + logique de validation côté client + business logique côté client + proxy WCF. Dans notre cas, vu le peu de complexité il s’agit essentiellement du DomainContext RIA Services &lt;/li&gt;
    &lt;li&gt;La vue : En Silverlight il s’agira d’un UserControl, ou d’une page (depuis Silverlight 3), avec peu (dans l’idéal pas) de code behind. &lt;/li&gt;
    &lt;li&gt;Le ViewModel : littéralement le “modèle de la vue”. Il s’agit d’une classe encapsulant le modèle de manière à le présenter à la vue de la manière la plus “bindable” possible. Le ViewModel expose dans certain cas directement des entités du modèle, dans d’autres il les encapsule pour les rendre plus “Silverlight-aware” (par exemple en présentant les propriétés booléennes sous forme de Visibility, en fournissant les ItemsSource des combobox / listbox etc, et en présentant les comportements sous forme de Commandes sur lesquelles la vue peut se “binder”). &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Un des enjeux majeurs est de faire en sorte d’avoir des vues en pur XAML, et des ViewModels complètement indépendants des vues qui leur seront associées, afin d’avoir un XAML entièrement modifiable par un designer sans que le comportement ne soit affecté.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Un autre enjeu est la testabilité des applications, et l’isolation des différents composants. Dans notre exemple, toutes les interdépendances seront résolues par injection de dépendance, à l’aide de Unity Application bloc&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Introduction à l’injection de dépendance avec Unity&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Le but de l’injection de dépendance est de réduire le couplage entre les différents composants d’une application. Ce pattern repose sur un composant central, le conteneur, qui permet de configurer la façon dont les différents composants seront résolus. Voici quelques exemples d’enregistrements de dépendances avec Unity:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: #2b91af"&gt;            IUnityContainer &lt;/span&gt;container = &lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;UnityContainer&lt;/span&gt;();
            
            &lt;span style="COLOR: green"&gt;// Map l'interface IMainViewModel à l'implémentation MainViewModel.
            // Chaque fois que l'on demandera un IMainViewModel à Unity, il créera une instance
            // de MainViewModel :
            &lt;/span&gt;container.RegisterType&amp;lt;&lt;span style="COLOR: #2b91af"&gt;IMainViewModel&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;MainViewModel&lt;/span&gt;&amp;gt;();
            
            &lt;span style="COLOR: green"&gt;// La même chose en mode "Singleton" (une seule instance sera créée
            // par le conteneur, qui sera renvoyé à chaque fois :
            &lt;/span&gt;container.RegisterType&amp;lt;&lt;span style="COLOR: #2b91af"&gt;IMainViewModel&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;MainViewModel&lt;/span&gt;&amp;gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;ContainerControlledLifetimeManager&lt;/span&gt;());

            &lt;span style="COLOR: green"&gt;// La même chose avec "une instance par thread" :
            &lt;/span&gt;container.RegisterType&amp;lt;&lt;span style="COLOR: #2b91af"&gt;IMainViewModel&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;MainViewModel&lt;/span&gt;&amp;gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;PerThreadLifetimeManager&lt;/span&gt;());

            &lt;span style="COLOR: green"&gt;// Spécifie comment notre DomainContext doit être construit
            // (ici en spécifiant un DomainClient de test plutot que le client Rest/HTTP):
            &lt;/span&gt;container.RegisterType&amp;lt;&lt;span style="COLOR: #2b91af"&gt;PeopleContext&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;PeopleContext&lt;/span&gt;&amp;gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;InjectionConstructor&lt;/span&gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;TestDomainClient()));&lt;/pre&gt;
&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;p&gt;Ensuite pour résoudre une dépendance on a juste à faire :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;var &lt;/span&gt;viewModel = container.Resolve&amp;lt;&lt;span style="COLOR: #2b91af"&gt;IMainViewModel&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Le fonctionnement basique de Unity est vraiment très simple. Il y’a pas mal d’autres fonctionnalités comme l’injection de propriétés, l’interception d’appels de méthode (DynamicProxy…) mais elles ne seront pas présentées dans cet article&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Configuration de l’application&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Dans cette application, nous n’avons qu’un seul ViewModel : MainViewModel. Ce ViewModel implémente IMainViewModel :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;namespace &lt;/span&gt;SilverlightSample.ViewModels
{
    &lt;span style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/span&gt;&lt;span style="COLOR: green"&gt;ViewModel exposing data and commands
    &lt;/span&gt;&lt;span style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;public interface &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;IMainViewModel
    &lt;/span&gt;{
        &lt;span style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/span&gt;&lt;span style="COLOR: green"&gt;The RIA Services exposed Data
        &lt;/span&gt;&lt;span style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
        &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;PeopleContext &lt;/span&gt;DomainContext { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; }

        &lt;span style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/span&gt;&lt;span style="COLOR: green"&gt;A command that needs a Person instance as a parameter
        &lt;/span&gt;&lt;span style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
        &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;ICommand &lt;/span&gt;FooCommand { &lt;span style="COLOR: blue"&gt;get&lt;/span&gt;; }
    }
}&lt;/pre&gt;
&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;L’implémentation de IMainViewModel expose le DomainContext RIA afin de fournir à la vue la possibilité de définir des DomainDataSources permettant aux contrôles DataGrid et DataPager de fonctionner correctement. On expose aussi une commande à laquelle la vue pourra se binder (voir les boutons Foo dans le screenshot en début de post). Le DomainContext sera résolu par Unity, tandis qu’une RelayCommand sera créée pour la propriété FooCommand :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;public class &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MainViewModel &lt;/span&gt;: &lt;span style="COLOR: #2b91af"&gt;IMainViewModel&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;IInitialize
    &lt;/span&gt;{
        &lt;span style="COLOR: blue"&gt;private &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;PeopleContext &lt;/span&gt;_domainContext;
        &lt;span style="COLOR: blue"&gt;private &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RelayCommand &lt;/span&gt;_fooCommand;
        &lt;span style="COLOR: #2b91af"&gt;IUnityContainer &lt;/span&gt;_unityContainer;
        &lt;span style="COLOR: blue"&gt;public &lt;/span&gt;MainViewModel(&lt;span style="COLOR: #2b91af"&gt;IUnityContainer &lt;/span&gt;unityContainer)
        {
            _unityContainer = unityContainer;

            _domainContext = unityContainer.Resolve&amp;lt;&lt;span style="COLOR: #2b91af"&gt;PeopleContext&lt;/span&gt;&amp;gt;();
          

            _fooCommand = &lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;RelayCommand&lt;/span&gt;(
                obj =&amp;gt; DoFoo(obj &lt;span style="COLOR: blue"&gt;as &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Person&lt;/span&gt;),
                obj =&amp;gt; obj &lt;span style="COLOR: blue"&gt;is &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;Person&lt;/span&gt;);
        }&lt;br /&gt;…&lt;br /&gt;}&lt;/pre&gt;
&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;p&gt;note : MainViewModel implémente aussi IInitialize. Cette interface est déclarée dans ma boîte à outils MVVM et est utilisée par le contrôle ViewModelHelper décrit un peu plus loin.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Au niveau du App.xaml, nous allons donc configurer notre conteneur de dépendances pour IMainViewModel et PeopleContext :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;private void &lt;/span&gt;Application_Startup(&lt;span style="COLOR: blue"&gt;object &lt;/span&gt;sender, &lt;span style="COLOR: #2b91af"&gt;StartupEventArgs &lt;/span&gt;e)
{
    &lt;span style="COLOR: #2b91af"&gt;IUnityContainer &lt;/span&gt;rootApplicationContainer = &lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;UnityContainer&lt;/span&gt;();
    rootApplicationContainer.RegisterType&amp;lt;&lt;span style="COLOR: #2b91af"&gt;IMainViewModel&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;MainViewModel&lt;/span&gt;&amp;gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;ContainerControlledLifetimeManager&lt;/span&gt;());
    rootApplicationContainer.RegisterType&amp;lt;&lt;span style="COLOR: #2b91af"&gt;PeopleContext&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;PeopleContext&lt;/span&gt;&amp;gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;InjectionConstructor&lt;/span&gt;()); &lt;br /&gt;//on spécifie explicitement&lt;br /&gt;// l’utilisation du constructeur par défaut
    Resources.Add(&lt;span style="COLOR: #a31515"&gt;"RootContainer"&lt;/span&gt;, rootApplicationContainer);

    &lt;span style="COLOR: blue"&gt;this&lt;/span&gt;.RootVisual = &lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;MainPage&lt;/span&gt;();
}&lt;/pre&gt;
&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;note : vous pouvez constater que l’on rajoute le conteneur aux ressources de l’Application afin de pouvoir y accéder de partout (y compris à partir du Xaml en utilisant une {StaticResource}).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Accéder au conteneur Unity depuis la vue&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Afin d’accéder au ViewModel via Unity à partir de ma vue, j’ai créé un contrôle ViewModelHelper. Ce contrôle n’a pas de template d’affichage et permet simple d’accéder à un ViewModel enregistré dans un conteneur Unity (un peu à la manière du DomainDataSource qui permet d’accèder aux entités d’un DomainContext).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;ViewModelHelper a les propriétés suivantes :&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;UnityContainer : le conteneur Unity utilisé pour résoudre le ViewModel &lt;/li&gt;
    &lt;li&gt;ViewModelType : le type du ViewModel (par exemple : “SilverlightSample.ViewModels.IMainViewModel, SilverlightSample, Version=1.0.0.0”) &lt;/li&gt;
    &lt;li&gt;ViewModelName (optionnel) : utilisé si l’enregistrement de la dépendance est nommé (paramètre optionnel de UnityContainer.RegisterType() et UnityContainer.Resolve()) &lt;/li&gt;
    &lt;li&gt;InitParam (optionnel) : paramètre à passer à la méthode Initialize si le ViewModel implémente IInitialize. &lt;/li&gt;
    &lt;li&gt;ViewModel (lecture seule) : le ViewModel résolu &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Dans notre exemple, la vue principale de l’application possède donc un ViewModelHelper :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;ViewModelHelper 
    &lt;/span&gt;&lt;span style="COLOR: red"&gt;UnityContainer&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="{&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;StaticResource &lt;/span&gt;&lt;span style="COLOR: red"&gt;RootContainer&lt;/span&gt;&lt;span style="COLOR: blue"&gt;}"
    &lt;/span&gt;&lt;span style="COLOR: red"&gt;ViewModelType&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="SilverlightSample.ViewModels.IMainViewModel,
                   SilverlightSample, Version=1.0.0.0"
    &lt;/span&gt;&lt;span style="COLOR: red"&gt;x&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: red"&gt;Name&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="vmh" /&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Comme Silverlight 3 introduit le Binding inter-contrôles, on peut alors se Binder au ViewModel ainsi exposé :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;ria&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;DomainDataSource &lt;/span&gt;&lt;span style="COLOR: red"&gt;x&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: red"&gt;Name&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="dds"
                              &lt;/span&gt;&lt;span style="COLOR: red"&gt;AutoLoad&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="True"                           
                              &lt;/span&gt;&lt;span style="COLOR: red"&gt;LoadMethodName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="LoadAllPeople"
                              &lt;/span&gt;&lt;span style="COLOR: red"&gt;DomainContext&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="{&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="COLOR: red"&gt;ViewModel&lt;/span&gt;&lt;span style="COLOR: blue"&gt;.&lt;/span&gt;&lt;span style="COLOR: red"&gt;DomainContext&lt;/span&gt;&lt;span style="COLOR: blue"&gt;, &lt;/span&gt;&lt;span style="COLOR: red"&gt;ElementName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=vmh}"
                              /&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;&lt;/span&gt; &lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;Comme la vue n’est pas liée à une implémentation particulière de IMainViewModel, on peut tout à fait imaginer créer des tests unitaires vérifiant par exemple la validité des bindings, en proposant un “mock” du ViewModel en lieu et place de l’implémentation normale (c’est d’ailleurs le cas dans la solution liée au post).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;note : Pourquoi ViewModelHelper est un contrôle ? Tout simplement pour pouvoir Binder son InitParam ou son ViewModelName à une propriété du DataContext (ce qui est très utile dans des scénarii de vues Master / Details où chaque vue détail est associé à un ViewModel).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Accéder au ViewModelHelper à partir d’une ligne du DataGrid&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Une des limites du Binding inter-éléments de Silverlight, est qu’il ne remonte pas au NameScope parent si il ne trouve pas l’UIElement dans le scope courrant. Hors, dans mon cas, la colonne de commande est réalisée grâce à une DataGridTemplatedColumn, basé sur un template qui génèrera donc pour chaque cellule un NameScope différent. Pour palier à ce problème, j’ai écrit un deuxième contrôle non-graphique utilisé simplement pour explorer l’arbre visuel : le VisualTreeDataSource.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Ce contrôle expose 2 propriétés : &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Query : n’importe quel objet implémentant IVisualTreeQuery (cette interface est vraiment très simple à implémenter, regardez les sources pour vous en convaincre) &lt;/li&gt;
    &lt;li&gt;Match (lecture seule) : contrôle retourné par la requète. Cette propriété est maintenue à jour à chaque évènement LayoutUpdated &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Voici donc le template utilisé pour la colonne de commandes :&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;DataTemplate&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Grid&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
        &lt;/span&gt;&lt;span style="COLOR: green"&gt;&amp;lt;!-- Element Binding do not work accross NameScopes.
        RelativeSource markup extension is lacking the FindAncestor mode--&amp;gt;
        &amp;lt;!-- So, the VisualTreeDataSource is used to find an element using VisualTree browsing--&amp;gt;
        &lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;VisualTreeDataSource &lt;/span&gt;&lt;span style="COLOR: red"&gt;x&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: red"&gt;Name&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="vds"&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;VisualTreeDataSource.Query&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;ComposedVisualQuery&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
                    &lt;/span&gt;&lt;span style="COLOR: green"&gt;&amp;lt;!-- first get the MainPage control--&amp;gt;
                    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;FindAncestor &lt;/span&gt;&lt;span style="COLOR: red"&gt;AncestorType&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="SilverlightSample.MainPage,
                                                       SilverlightSample,Version=1.0.0.0" /&amp;gt;
                    &lt;/span&gt;&lt;span style="COLOR: green"&gt;&amp;lt;!-- then find the control named "vmh"--&amp;gt;
                    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;FindName &lt;/span&gt;&lt;span style="COLOR: red"&gt;TargetName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="vmh" /&amp;gt;
                &amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;ComposedVisualQuery&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;VisualTreeDataSource.Query&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;VisualTreeDataSource&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
        &lt;/span&gt;&lt;span style="COLOR: green"&gt;&amp;lt;!-- Now we can access the ViewModelHelper via the Match DependencyProperty 
        of the VisualTreeDataSource and bind to exposed command--&amp;gt;
        &lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Button &lt;/span&gt;&lt;span style="COLOR: red"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: red"&gt;Commanding.Command&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="{&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="COLOR: red"&gt;Match&lt;/span&gt;&lt;span style="COLOR: blue"&gt;.&lt;/span&gt;&lt;span style="COLOR: red"&gt;ViewModel&lt;/span&gt;&lt;span style="COLOR: blue"&gt;.FooCommand, &lt;/span&gt;&lt;span style="COLOR: red"&gt;ElementName&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=vds}"
                &lt;/span&gt;&lt;span style="COLOR: red"&gt;sstuff&lt;/span&gt;&lt;span style="COLOR: blue"&gt;:&lt;/span&gt;&lt;span style="COLOR: red"&gt;Commanding.CommandParameter&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="{&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Binding&lt;/span&gt;&lt;span style="COLOR: blue"&gt;}" 
                &lt;/span&gt;&lt;span style="COLOR: red"&gt;Content&lt;/span&gt;&lt;span style="COLOR: blue"&gt;="Foo"/&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Grid&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;DataTemplate&lt;/span&gt;&lt;span style="COLOR: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;Et voilà, nous avons une vue qui accède à son ViewModel via Unity et qui n’a aucun CodeBehind.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Voici les différents points que j’ai abordé dans ce post :&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Intégrer les RIA Services au pattern MVVM (dans ma wish-list, j’aimerais bien pouvoir me passer du DomainDataSource dans les vues tout en gardant la possibilité de tri / pagination côté server et donc ne plus être obligé d’exposé le DomainContext complet, qui n’est pas très simple à mocker) &lt;/li&gt;
    &lt;li&gt;Utiliser les nouvelles fonctionnalités de Binding de Silverlight 3 pour créer des vues “CodeBehind-less” &lt;/li&gt;
    &lt;li&gt;Réduire le couplage entre la vue et le ViewModel, et entre le ViewModel et le modèle afin d’améliorer la testabilité des composants de façon unitaire (Injection de dépendance avec Unity) &lt;/li&gt;
    &lt;li&gt;Accéder au conteneur Unity en pur Xaml pour la résolution des ViewModels &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Ce que je n’ai pas abordé dans le post mais que vous pouvez trouver dans la solution téléchargeable : l’écriture des tests unitaires de la vue (par mocking du ViewModel) et du ViewModel (par mocking du DomainClient utilisé par le PeopleContext).&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id="scid:F60BB8FA-6F02-4999-8F5E-9DD4E92C4DA7:c9b9f80f-6f74-4b8d-8ca0-c9f0325ada88" class="wlWriterEditableSmartContent"&gt;
&lt;div&gt;&lt;a target="_self" href="http://simonferquel.net/blog/images/simonferquel_net/blog/WindowsLiveWriter/SilverlightSilverlight3RIAServicesMVVMet_F519/solution.zip"&gt;Téléchargez la solution&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/48.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=Bl7zG41NP98:iDdGVn7VIco:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=Bl7zG41NP98:iDdGVn7VIco:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=Bl7zG41NP98:iDdGVn7VIco:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=Bl7zG41NP98:iDdGVn7VIco:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=Bl7zG41NP98:iDdGVn7VIco:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/Bl7zG41NP98" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/03/25/silverlight-silverlight-3--ria-services--mvvm-et-testabiliteacute.aspx</guid>
            <pubDate>Wed, 25 Mar 2009 16:46:00 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/48.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/03/25/silverlight-silverlight-3--ria-services--mvvm-et-testabiliteacute.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/48.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/48.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/03/25/silverlight-silverlight-3--ria-services--mvvm-et-testabiliteacute.aspx</feedburner:origLink></item>
        <item>
            <title>[Silverlight] AutoCompleteBox et Binding sur SelectedItem</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/n-JzzotHpTE/silverlight-autocompletebox-et-binding-sur-selecteditem.aspx</link>
            <description>&lt;p&gt;Le Silverlight Control Toolkit comprend un contrôle fort utile pour les applications RIA : l’AutoCompleteBox. Malheureusement, sa propriété SelectedItem est en lecture seule, et ne permet donc pas de faire du Binding dessus. Il existe 2 solutions à ce problème :&lt;/p&gt;  &lt;p&gt;1. Télécharger les sources associées au ChangeSet 10371 ou supérieur sur le site CodePlex et recompiler le toolkit&lt;/p&gt;  &lt;p&gt;2. Passer par une attached property (seule solution garantissant qu’il n’y ait pas de Breaking Change):&lt;/p&gt;  &lt;p&gt;public class AutoCompleteHelper : DependencyObject   &lt;br /&gt;    {    &lt;br /&gt;        public static bool GetBound(DependencyObject obj)    &lt;br /&gt;        {    &lt;br /&gt;            return (bool)obj.GetValue(BoundProperty);    &lt;br /&gt;        } &lt;/p&gt;  &lt;p&gt;        public static void SetBound(DependencyObject obj, bool value)   &lt;br /&gt;        {    &lt;br /&gt;            obj.SetValue(BoundProperty, value);    &lt;br /&gt;        } &lt;/p&gt;  &lt;p&gt;        // Using a DependencyProperty as the backing store for Bound.  This enables animation, styling, binding, etc...   &lt;br /&gt;        public static readonly DependencyProperty BoundProperty =    &lt;br /&gt;            DependencyProperty.RegisterAttached("Bound", typeof(bool), typeof(AutoCompleteHelper), new PropertyMetadata(false,    &lt;br /&gt;                (sender, args) =&amp;gt;    &lt;br /&gt;                { &lt;/p&gt;  &lt;p&gt;                    var box = sender as AutoCompleteBox;   &lt;br /&gt;                    if ((bool)args.NewValue)    &lt;br /&gt;                        box.SelectionChanged += box_SelectionChanged;    &lt;br /&gt;                    else    &lt;br /&gt;                        box.SelectionChanged -= box_SelectionChanged;    &lt;br /&gt;                })); &lt;/p&gt;  &lt;p&gt;        static void box_SelectionChanged(object sender, SelectionChangedEventArgs e)   &lt;br /&gt;        {    &lt;br /&gt;            var box = sender as AutoCompleteBox;    &lt;br /&gt;            SetSelectedItem(box, box.SelectedItem);    &lt;br /&gt;        } &lt;/p&gt;  &lt;p&gt;        public static object GetSelectedItem(AutoCompleteBox obj)   &lt;br /&gt;        {    &lt;br /&gt;            return (object)obj.GetValue(SelectedItemProperty);    &lt;br /&gt;        } &lt;/p&gt;  &lt;p&gt;        public static void SetSelectedItem(AutoCompleteBox obj, object value)   &lt;br /&gt;        {    &lt;br /&gt;            obj.SetValue(SelectedItemProperty, value);    &lt;br /&gt;        } &lt;/p&gt;  &lt;p&gt;        // Using a DependencyProperty as the backing store for SelectedItem.  This enables animation, styling, binding, etc...   &lt;br /&gt;        public static readonly DependencyProperty SelectedItemProperty =    &lt;br /&gt;            DependencyProperty.RegisterAttached("SelectedItem", typeof(object), typeof(AutoCompleteHelper), new PropertyMetadata(null,    &lt;br /&gt;                (sender, args) =&amp;gt;    &lt;br /&gt;                {    &lt;br /&gt;                    var box = sender as AutoCompleteBox;    &lt;br /&gt;                    var txt = string.Empty;    &lt;br /&gt;                    if (args.NewValue != null)    &lt;br /&gt;                        txt = args.NewValue.ToString();    &lt;br /&gt;                    box.Text = txt;    &lt;br /&gt;                    SetBound(box, true);    &lt;br /&gt;                })); &lt;/p&gt;  &lt;p&gt;    }&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;Ensuite, dans le xaml il suffira de faire:&lt;/p&gt;  &lt;p&gt;&amp;lt;tk:AutoCompleteBox  ItemsSource="{Binding ItemsSource}"    &lt;br /&gt;                                    c:AutoCompleteHelper.SelectedItem="{Binding TheSelectedItem, Mode=TwoWay}"     &lt;br /&gt;                                    c:AutoCompleteHelper.Bound="true"  /&amp;gt;&lt;/p&gt;  &lt;p&gt;Enjoy !&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/47.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=n-JzzotHpTE:ekY8MBSYj08:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=n-JzzotHpTE:ekY8MBSYj08:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=n-JzzotHpTE:ekY8MBSYj08:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=n-JzzotHpTE:ekY8MBSYj08:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=n-JzzotHpTE:ekY8MBSYj08:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/n-JzzotHpTE" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/03/11/silverlight-autocompletebox-et-binding-sur-selecteditem.aspx</guid>
            <pubDate>Wed, 11 Mar 2009 12:14:56 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/47.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/03/11/silverlight-autocompletebox-et-binding-sur-selecteditem.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/47.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/47.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/03/11/silverlight-autocompletebox-et-binding-sur-selecteditem.aspx</feedburner:origLink></item>
        <item>
            <title>[Surface] Winwise a re&amp;ccedil;u sa table&amp;hellip;</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/E3gKhtSpeHw/surface-winwise-a-reccedilu-sa-tablehellip.aspx</link>
            <description>&lt;p&gt;… et on est super content, la preuve en video, apres 1H30 de dev (dont 1H15 de recherche d’image / musique ^^):&lt;/p&gt;  &lt;p&gt;&lt;iframe style="padding-bottom: 0px; margin: 0px; padding-left: 0px; width: 100%; padding-right: 0px; height: 375px; overflow: hidden; padding-top: 0px" id="dm_jukebox_iframe" marginheight="0" src="http://www.dailymotion.com/widget/jukebox?list[]=%2Fplaylist%2Fxv1wy_Simon_Ferquel_surface" frameborder="0" width="100%" marginwidth="0" align="center"&gt;&lt;/iframe&gt;&lt;/p&gt;  &lt;p&gt;Si vous avez des idées débiles (ou pas) autour de Surface, mais que vous n’avez pas la table / le SDK pour les réaliser, vous pouvez me contacter pour que l’on travaille dessus et je me ferai un plaisir de refaire des petites videos dans le genre…&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;/love Surface&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:7aa4d17b-7cda-4372-9372-5807fa7b2064" class="wlWriterEditableSmartContent"&gt;Mots clés Technorati : &lt;a href="http://technorati.com/tags/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Surface" rel="tag"&gt;Surface&lt;/a&gt;,&lt;a href="http://technorati.com/tags/WPF" rel="tag"&gt;WPF&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Fun" rel="tag"&gt;Fun&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/46.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=E3gKhtSpeHw:pNYoB-bwtDU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=E3gKhtSpeHw:pNYoB-bwtDU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=E3gKhtSpeHw:pNYoB-bwtDU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=E3gKhtSpeHw:pNYoB-bwtDU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=E3gKhtSpeHw:pNYoB-bwtDU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/E3gKhtSpeHw" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/02/24/surface-winwise-a-reccedilu-sa-tablehellip.aspx</guid>
            <pubDate>Mon, 23 Feb 2009 23:46:25 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/46.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/02/24/surface-winwise-a-reccedilu-sa-tablehellip.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/46.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/46.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/02/24/surface-winwise-a-reccedilu-sa-tablehellip.aspx</feedburner:origLink></item>
        <item>
            <title>[Silverlight 2] PasswordBox et DataBinding</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/zqy0hXoPPx8/silverlight-2-passwordbox-et-databinding.aspx</link>
            <description>&lt;p&gt;Silverlight 2 introduit le contrôle “PasswordBox” qui permet d’entrer un mot de passe sans qu’il n’apparaisse en clair à l’écran. Le problème de ce contrôle est qu’il ne supporte pas le DataBinding sur sa propriété “Password”. En effet, si on lui affecte un Binding, une exception est levée (avec par ailleurs un message d’erreur pour le moins obscure).&lt;/p&gt;  &lt;p&gt;Afin d’ajouter des possibilités de Binding à ce contrôle, on aurait pu en hériter et modifier son comportement. Mais cette approche est très intrusive et oblige l’utilisateur à utiliser ce nouveau contrôle. Une approche plus élégante est d’utiliser une AttachedProperty comme Pierre Lagarde nous l’a montré mercredi dernier lors de la session “Développement de contrôles avec Silverlight 2” qu’il co-animait avec Thierry Bouquain et moi, avec son exemple d’image downloader. En effet, une AttachedProperty étant une DependencyProperty spéciale, elle supporte le DataBinding, et nous pouvons donc écrire une propriété “proxy” permettant de faire le lien vers la propriété Password d’une PropertyBox.&lt;/p&gt;  &lt;p&gt;Voici le code utilisé (fournit dans SLExtension) :&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Net;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Controls;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Documents;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Ink;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Input;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Media;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Media.Animation;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Windows.Shapes;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;SLExtensions
{
    &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/span&gt;&lt;span style="color: green"&gt;Provide attached property to enable DataBinding on PasswordBox
    &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
    &lt;/span&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PasswordHelper &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;DependencyObject
    &lt;/span&gt;{

        &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/span&gt;&lt;span style="color: green"&gt;Indicates if a PasswordBox is DataBound
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name="obj"&amp;gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
        &lt;/span&gt;&lt;span style="color: blue"&gt;public static bool &lt;/span&gt;GetIsBound(&lt;span style="color: #2b91af"&gt;PasswordBox &lt;/span&gt;obj)
        {
            &lt;span style="color: blue"&gt;return &lt;/span&gt;(&lt;span style="color: blue"&gt;bool&lt;/span&gt;)obj.GetValue(IsBoundProperty);
        }

        &lt;span style="color: blue"&gt;private static void &lt;/span&gt;SetIsBound(&lt;span style="color: #2b91af"&gt;PasswordBox &lt;/span&gt;obj, &lt;span style="color: blue"&gt;bool &lt;/span&gt;value)
        {
            obj.SetValue(IsBoundProperty, value);
        }

        &lt;span style="color: blue"&gt;public static readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DependencyProperty &lt;/span&gt;IsBoundProperty =
            &lt;span style="color: #2b91af"&gt;DependencyProperty&lt;/span&gt;.RegisterAttached(&lt;span style="color: #a31515"&gt;"IsBound"&lt;/span&gt;, &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: blue"&gt;bool&lt;/span&gt;), 
            &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;PasswordHelper&lt;/span&gt;), 
            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyMetadata&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;));


        &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/span&gt;&lt;span style="color: green"&gt;Text of the PasswordBox (bindable vision of Password property)
        &lt;/span&gt;&lt;span style="color: gray"&gt;/// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name="obj"&amp;gt;&amp;lt;/param&amp;gt;
        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
        &lt;/span&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;GetText(&lt;span style="color: #2b91af"&gt;PasswordBox &lt;/span&gt;obj)
        {
            &lt;span style="color: blue"&gt;return &lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;)obj.GetValue(TextProperty);
        }

        &lt;span style="color: blue"&gt;public static void &lt;/span&gt;SetText(&lt;span style="color: #2b91af"&gt;PasswordBox &lt;/span&gt;obj, &lt;span style="color: blue"&gt;string &lt;/span&gt;value)
        {
            obj.SetValue(TextProperty, value);
        }

        &lt;span style="color: blue"&gt;public static readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DependencyProperty &lt;/span&gt;TextProperty =
            &lt;span style="color: #2b91af"&gt;DependencyProperty&lt;/span&gt;.RegisterAttached(&lt;span style="color: #a31515"&gt;"Text"&lt;/span&gt;, &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;),
            &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;PasswordHelper&lt;/span&gt;), 
            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyMetadata&lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;.Empty,
                (sender, args) =&amp;gt;
                {
                    &lt;span style="color: blue"&gt;var &lt;/span&gt;pwdBox = sender &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PasswordBox&lt;/span&gt;;
                    &lt;span style="color: blue"&gt;if &lt;/span&gt;(pwdBox == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                        &lt;span style="color: blue"&gt;return&lt;/span&gt;;
                    &lt;span style="color: blue"&gt;var &lt;/span&gt;nval = (args.NewValue &lt;span style="color: blue"&gt;as string&lt;/span&gt;) ?? &lt;span style="color: blue"&gt;string&lt;/span&gt;.Empty;
                    &lt;span style="color: blue"&gt;if&lt;/span&gt;(pwdBox.Password != nval)
                        pwdBox.Password = nval;
                    &lt;span style="color: blue"&gt;if &lt;/span&gt;(!GetIsBound(pwdBox))
                    {
                        pwdBox.PasswordChanged += &lt;span style="color: blue"&gt;delegate
                        &lt;/span&gt;{
                            SetText(pwdBox, pwdBox.Password);
                        };
                        SetIsBound(pwdBox, &lt;span style="color: blue"&gt;true&lt;/span&gt;);
                    }
                }));
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Et à l’utilisation, il suffit maintenant de faire :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;PasswordBox &lt;/span&gt;&lt;span style="color: red"&gt;sle&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: red"&gt;PasswordHelper.Text&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;,&lt;/span&gt;&lt;span style="color: red"&gt;Mode&lt;/span&gt;&lt;span style="color: blue"&gt;=TwoWay}" /&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;span style="color: blue"&gt;&lt;/span&gt;&lt;/p&gt;
Enjoy !&lt;img src="http://www.simonferquel.net//blog/aggbug/45.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=zqy0hXoPPx8:gr_b6AnW2Nc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=zqy0hXoPPx8:gr_b6AnW2Nc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=zqy0hXoPPx8:gr_b6AnW2Nc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=zqy0hXoPPx8:gr_b6AnW2Nc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=zqy0hXoPPx8:gr_b6AnW2Nc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/zqy0hXoPPx8" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/02/16/silverlight-2-passwordbox-et-databinding.aspx</guid>
            <pubDate>Mon, 16 Feb 2009 15:59:47 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/45.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/02/16/silverlight-2-passwordbox-et-databinding.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/45.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/45.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/02/16/silverlight-2-passwordbox-et-databinding.aspx</feedburner:origLink></item>
        <item>
            <title>[WCF] Validation des entr&amp;eacute;es</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/kxYkU47ZWiw/wcf-validation-des-entreacutees.aspx</link>
            <description>&lt;p&gt;J'étais il y a quelques jours en mission de conseil sur WCF, et je suis tombé sur une erreur assez typique dans des solutions basées sur une plateforme de Services exposée sur Internet. Il s'agit du degré de confiance que l'on a tendance à avoir envers le client. Voici par exemple un morceau de code assez typique : &lt;/p&gt;  &lt;p&gt;Contrats : &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;System;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Collections.Generic;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Linq;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Text;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.ServiceModel;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Runtime.Serialization;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;ServiceContracts
{
    [&lt;span style="color: #2b91af"&gt;DataContract&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Consumer
    &lt;/span&gt;{
        [&lt;span style="color: #2b91af"&gt;DataMember&lt;/span&gt;]
        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;ID { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
        [&lt;span style="color: #2b91af"&gt;DataMember&lt;/span&gt;]
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;Name { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
        [&lt;span style="color: #2b91af"&gt;DataMember&lt;/span&gt;]
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;Email { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
    }


    [&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMyConsumersService
    &lt;/span&gt;{
        [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;]
        &lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Consumer&lt;/span&gt;&amp;gt; GetConsumersPage( &lt;span style="color: blue"&gt;int &lt;/span&gt;pageIndex, &lt;span style="color: blue"&gt;int &lt;/span&gt;pageSize, &lt;span style="color: blue"&gt;out int &lt;/span&gt;pageCount);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Implémentation :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MyConsumersService &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IMyConsumersService
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;#region &lt;/span&gt;IMyConsumersService Members

        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Consumer&lt;/span&gt;&amp;gt; GetConsumersPage(&lt;span style="color: blue"&gt;int &lt;/span&gt;pageIndex, &lt;span style="color: blue"&gt;int &lt;/span&gt;pageSize, &lt;span style="color: blue"&gt;out int &lt;/span&gt;pageCount)
        {
            &lt;span style="color: green"&gt;// Security Checks
            &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;userID = &lt;span style="color: #2b91af"&gt;SecurityHelper&lt;/span&gt;.GetCurrentUserID();
            &lt;span style="color: #2b91af"&gt;SecurityHelper&lt;/span&gt;.AssertPermission(userID, &lt;span style="color: #2b91af"&gt;Permission&lt;/span&gt;.BrowseConsumers);

            &lt;span style="color: #2b91af"&gt;IConsumerProvider &lt;/span&gt;dataProvider = &lt;span style="color: #2b91af"&gt;ServiceProvider&lt;/span&gt;.GetService&amp;lt;&lt;span style="color: #2b91af"&gt;IConsumerProvider&lt;/span&gt;&amp;gt;();
            &lt;span style="color: blue"&gt;return &lt;/span&gt;dataProvider.GetConsumersOfUser(userID, pageIndex, pageSize, &lt;span style="color: blue"&gt;out &lt;/span&gt;pageCount);
        }

        &lt;span style="color: blue"&gt;#endregion
    &lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Dans cet exemple, on peut déjà voir des pratiques tout à fait bonnes : Injection de dépendance pour ne pas référencer la couche DAL directement (idéal pour assurer la testabilité du service en "Mockant" la DAL), ainsi qu'une gestion centralisée des permissions des utilisateurs, afin de ne pas polluer outre mesure le code des services, qui doit se concentrer sur le métier.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Il y a cependant quelque chose qui ne va pas quand on sait que ce service est sensé être accessible depuis Internet, et voici donc la question que j'ai posée à mon client : "Comment pouvez vous être sûr que le client ne va pas vous demander 1500000 lignes et ainsi consommer beaucoup plus de ressources que ce que vous ne voudriez ?". &lt;/p&gt;

&lt;p&gt;La réponse fut : "L'application cliente ne propose que 3 options : 5, 20, et 100 lignes par page".&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;C'est exactement le genre de justification complètement invalide dans un scénario tel que celui là : De même que l'on ne peut faire confiance en l'utilisateur qui appelle le service (ainsi on effectue des assertions pour vérifier qu'il possède les droits nécessaire), nous ne pouvons pas faire confiance en l'application cliente, car rien n'empêche aux utilisateurs du service de développer leurs propres applications consommant ce service, adaptées à leurs propres besoins métiers. Ainsi, nous devons donc faire une validation des paramètres d'entrée afin d'imposer des limites.&lt;/p&gt;

&lt;p&gt;La manière la plus simple de prime abord (et dans ce cas précis, c'est certainement la meilleure solution, vu le peu de paramètres à valider), est de faire une validation manuelle dans le code du service lui-même :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Consumer&lt;/span&gt;&amp;gt; GetConsumersPage(&lt;span style="color: blue"&gt;int &lt;/span&gt;pageIndex, &lt;span style="color: blue"&gt;int &lt;/span&gt;pageSize, &lt;span style="color: blue"&gt;out int &lt;/span&gt;pageCount)
        {
            &lt;span style="color: green"&gt;// Security Checks
            &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;userID = &lt;span style="color: #2b91af"&gt;SecurityHelper&lt;/span&gt;.GetCurrentUserID();
            &lt;span style="color: #2b91af"&gt;SecurityHelper&lt;/span&gt;.AssertPermission(userID, &lt;span style="color: #2b91af"&gt;Permission&lt;/span&gt;.BrowseConsumers);

            &lt;span style="color: green"&gt;// Technical validation :
            &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidationResume &lt;/span&gt;resume = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidationResume&lt;/span&gt;();
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(pageIndex &amp;lt; 0)
                resume.Entries.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidationEntry &lt;/span&gt;{ Name = &lt;span style="color: #a31515"&gt;"pageIndex"&lt;/span&gt;, &lt;br /&gt;                  ValidationMessage = &lt;span style="color: #a31515"&gt;"pageIndex should be &amp;gt;= 0" &lt;/span&gt;});
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(pageSize &amp;gt; 200)
                resume.Entries.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidationEntry &lt;/span&gt;{ Name = &lt;span style="color: #a31515"&gt;"pageSize"&lt;/span&gt;, &lt;br /&gt;                  ValidationMessage = &lt;span style="color: #a31515"&gt;"pageSize cannot be &amp;gt; 200" &lt;/span&gt;});
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(resume.Entries.Count &amp;gt; 0)
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FaultException&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;ValidationResume&lt;/span&gt;&amp;gt;(resume);

            &lt;span style="color: #2b91af"&gt;IConsumerProvider &lt;/span&gt;dataProvider = &lt;span style="color: #2b91af"&gt;ServiceProvider&lt;/span&gt;.GetService&amp;lt;&lt;span style="color: #2b91af"&gt;IConsumerProvider&lt;/span&gt;&amp;gt;();
            &lt;span style="color: blue"&gt;return &lt;/span&gt;dataProvider.GetConsumersOfUser(userID, pageIndex, pageSize, &lt;span style="color: blue"&gt;out &lt;/span&gt;pageCount);
        }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Le problème de cette technique c'est qu'elle est très intrusive vis à vis du code métier. Sur un projet d'une certaine taille, cela peut devenir compliqué à maintenir, et représenter un volume de code très conséquent qu'il peut être très tentant de factoriser. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;WCF nous permet de faire ce genre de choses, en créant un attribut implémentant IOperationBehavior qui nous permettra d'injecter notre code dans la stack WCF côté serveur ou côté client, et nous permettant de faire notre validation avant même l'appel de la méthode. Pour ceci, nous devrons aussi implémenter l'interface IParameterInspector fournie par WCF. Notre implémentation regardera des Attributs que nous placerons sur les paramètres de nos OperationContracts afin de les valider à chaque appel.&lt;/p&gt;

&lt;p&gt;Interface IValidator et attributs applicables sur des paramètres de méthode :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IValueValidator
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;bool &lt;/span&gt;Validate(&lt;span style="color: blue"&gt;object &lt;/span&gt;value, &lt;span style="color: blue"&gt;out string &lt;/span&gt;validationMessage);
    }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;AttributeTargets&lt;/span&gt;.Property | &lt;span style="color: #2b91af"&gt;AttributeTargets&lt;/span&gt;.Parameter)]
    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MaxValueAttribute &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Attribute&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;IValueValidator
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;private double &lt;/span&gt;_compareValue;

        &lt;span style="color: blue"&gt;public &lt;/span&gt;MaxValueAttribute(&lt;span style="color: blue"&gt;double &lt;/span&gt;maxValue)
        {
            _compareValue = maxValue;
        }

        &lt;span style="color: blue"&gt;#region &lt;/span&gt;IValueValidator Members

        &lt;span style="color: blue"&gt;public bool &lt;/span&gt;Validate(&lt;span style="color: blue"&gt;object &lt;/span&gt;value, &lt;span style="color: blue"&gt;out string &lt;/span&gt;validationMessage)
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;toCompare = &lt;span style="color: #2b91af"&gt;Convert&lt;/span&gt;.ToDouble(value);
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(toCompare &amp;gt; _compareValue)
            {
                validationMessage = &lt;span style="color: #a31515"&gt;"Maximum value is " &lt;/span&gt;+ _compareValue.ToString();
                &lt;span style="color: blue"&gt;return false&lt;/span&gt;;
            }
            validationMessage = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
            &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
        }

        &lt;span style="color: blue"&gt;#endregion
    &lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;Classe implémentant IParameterInspector et permettant l'exécution des différents validateurs :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;OperationInputValidator &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IParameterInspector
    &lt;/span&gt;{
        &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;ValidatorEntry&lt;/span&gt;&amp;gt; _validators;
        &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MethodInfo &lt;/span&gt;_operationContractInfo;
        &lt;span style="color: blue"&gt;public &lt;/span&gt;OperationInputValidator(&lt;span style="color: #2b91af"&gt;MethodInfo &lt;/span&gt;operationContractInfo)
        {
            _operationContractInfo = operationContractInfo;
            _validators = &lt;span style="color: #2b91af"&gt;ValidatorEntry&lt;/span&gt;.GetValidators(operationContractInfo).ToList();
        }
        &lt;span style="color: blue"&gt;private class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidatorEntry
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;public string &lt;/span&gt;ParameterName { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
            &lt;span style="color: blue"&gt;public int &lt;/span&gt;ParameterIndex { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
            &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IValueValidator &lt;/span&gt;Validator { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }

            &lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;ValidatorEntry&lt;/span&gt;&amp;gt; GetValidators(&lt;span style="color: #2b91af"&gt;MethodInfo &lt;/span&gt;operationContractInfo)
            {
                &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;param &lt;span style="color: blue"&gt;in &lt;/span&gt;operationContractInfo.GetParameters())
                {
                    &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;validator &lt;span style="color: blue"&gt;in &lt;/span&gt;param.GetCustomAttributes(&lt;span style="color: blue"&gt;false&lt;/span&gt;).OfType&amp;lt;&lt;span style="color: #2b91af"&gt;IValueValidator&lt;/span&gt;&amp;gt;())
                    {
                        &lt;span style="color: blue"&gt;yield return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidatorEntry
                        &lt;/span&gt;{
                            ParameterIndex = param.Position,
                            ParameterName = param.Name,
                            Validator = validator
                        };
                    }
                }
            }
        }


        &lt;span style="color: blue"&gt;#region &lt;/span&gt;IParameterInspector Members

        &lt;span style="color: blue"&gt;public void &lt;/span&gt;AfterCall(&lt;span style="color: blue"&gt;string &lt;/span&gt;operationName, &lt;span style="color: blue"&gt;object&lt;/span&gt;[] outputs, &lt;span style="color: blue"&gt;object &lt;/span&gt;returnValue, &lt;span style="color: blue"&gt;object &lt;/span&gt;correlationState)
        {
        }

        &lt;span style="color: blue"&gt;public object &lt;/span&gt;BeforeCall(&lt;span style="color: blue"&gt;string &lt;/span&gt;operationName, &lt;span style="color: blue"&gt;object&lt;/span&gt;[] inputs)
        {
            &lt;span style="color: #2b91af"&gt;ValidationResume &lt;/span&gt;resume = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidationResume&lt;/span&gt;();
            &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;validator &lt;span style="color: blue"&gt;in &lt;/span&gt;_validators)
            {
                &lt;span style="color: blue"&gt;string &lt;/span&gt;validationMessage;
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(!validator.Validator.Validate(inputs[validator.ParameterIndex], &lt;span style="color: blue"&gt;out &lt;/span&gt;validationMessage))
                {
                    resume.Entries.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ValidationEntry
                    &lt;/span&gt;{
                        Name = validator.ParameterName,
                        ValidationMessage = validationMessage
                    });
                }
            }
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(resume.Entries.Count &amp;gt; 0)
                &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FaultException&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;ValidationResume&lt;/span&gt;&amp;gt;(resume,resume.ToString());
            &lt;span style="color: blue"&gt;return null&lt;/span&gt;;
        }

        &lt;span style="color: blue"&gt;#endregion
    &lt;/span&gt;}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Attribut branchant le ParameterInspector sur un OperationContract WCF :&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;AttributeTargets&lt;/span&gt;.Method, Inherited = &lt;span style="color: blue"&gt;false&lt;/span&gt;)]
    &lt;span style="color: blue"&gt;public sealed class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RequiresInputValidationAttribute &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Attribute&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;IOperationBehavior
    &lt;/span&gt;{

        &lt;span style="color: blue"&gt;#region &lt;/span&gt;IOperationBehavior Members

        &lt;span style="color: blue"&gt;public void &lt;/span&gt;AddBindingParameters(&lt;span style="color: #2b91af"&gt;OperationDescription &lt;/span&gt;operationDescription, &lt;br /&gt;             System.ServiceModel.Channels.&lt;span style="color: #2b91af"&gt;BindingParameterCollection &lt;/span&gt;bindingParameters)
        {
            
        }

        &lt;span style="color: blue"&gt;public void &lt;/span&gt;ApplyClientBehavior(&lt;span style="color: #2b91af"&gt;OperationDescription &lt;/span&gt;operationDescription, &lt;br /&gt;             System.ServiceModel.Dispatcher.&lt;span style="color: #2b91af"&gt;ClientOperation &lt;/span&gt;clientOperation)
        {
        }

        &lt;span style="color: blue"&gt;public void &lt;/span&gt;ApplyDispatchBehavior(&lt;span style="color: #2b91af"&gt;OperationDescription &lt;/span&gt;operationDescription, &lt;br /&gt;             System.ServiceModel.Dispatcher.&lt;span style="color: #2b91af"&gt;DispatchOperation &lt;/span&gt;dispatchOperation)
        {
            dispatchOperation.ParameterInspectors.Add(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;OperationInputValidator&lt;/span&gt;(operationDescription.SyncMethod));
        }

        &lt;span style="color: blue"&gt;public void &lt;/span&gt;Validate(&lt;span style="color: #2b91af"&gt;OperationDescription &lt;/span&gt;operationDescription)
        {
        }

        &lt;span style="color: blue"&gt;#endregion
    &lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Et maintenant, nous pouvons modifier notre contrat de service afin de valider automatiquement les paramètres grâce à des attributs :&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMyConsumersService
    &lt;/span&gt;{
        [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;]
        [&lt;span style="color: #2b91af"&gt;RequiresInputValidation&lt;/span&gt;]
        [&lt;span style="color: #2b91af"&gt;FaultContract&lt;/span&gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ValidationResume&lt;/span&gt;))]
        &lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Consumer&lt;/span&gt;&amp;gt; GetConsumersPage
            ([&lt;span style="color: #2b91af"&gt;MinValue&lt;/span&gt;(0)] &lt;span style="color: blue"&gt;int &lt;/span&gt;pageIndex, [&lt;span style="color: #2b91af"&gt;MinValue&lt;/span&gt;(1), &lt;span style="color: #2b91af"&gt;MaxValue&lt;/span&gt;(100)] &lt;span style="color: blue"&gt;int &lt;/span&gt;pageSize, &lt;span style="color: blue"&gt;out int &lt;/span&gt;pageCount);
    }&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;La mise en place de cette technique est assez complexe, mais se fait très vite oubliée à l'utilisation. En effet, tout se fait de manière déclarative et très concise : si l'on ne considère que la modification apportée au contrat de service, cela a effectivement un aspect très simple, et à la portée de n'importe quel développeur. Sur un gros projet invoquant des développeurs d'un niveau inégal, ceci reste donc tout à fait exploitable. &lt;/p&gt;

&lt;p&gt;Un autre aspect de ce modèle est son extensibilité. En effet, pour rajouter une règle de validation, il suffit d'écrire une classe dérivant de Attribute et implémentant IValueValidator. Voici par exemple une autre règle interdisant une valeur nulle :&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;AttributeTargets&lt;/span&gt;.Parameter)]
    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RequiredAttribute &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Attribute&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;IValueValidator
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;#region &lt;/span&gt;IValueValidator Members

        &lt;span style="color: blue"&gt;public bool &lt;/span&gt;Validate(&lt;span style="color: blue"&gt;object &lt;/span&gt;value, &lt;span style="color: blue"&gt;out string &lt;/span&gt;validationMessage)
        {
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(value == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            {
                validationMessage = &lt;span style="color: #a31515"&gt;"Value must not be null"&lt;/span&gt;;
                &lt;span style="color: blue"&gt;return false&lt;/span&gt;;
            }
            &lt;span style="color: blue"&gt;var &lt;/span&gt;asString = value &lt;span style="color: blue"&gt;as string&lt;/span&gt;;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(asString != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; asString.Length == 0)
            {
                validationMessage = &lt;span style="color: #a31515"&gt;"Value must not be empty"&lt;/span&gt;;
                &lt;span style="color: blue"&gt;return false&lt;/span&gt;;
            }

            validationMessage = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
            &lt;span style="color: blue"&gt;return true&lt;/span&gt;;
        }

        &lt;span style="color: blue"&gt;#endregion
    &lt;/span&gt;}&lt;/pre&gt;

&lt;p&gt;Nous pouvons alors placer un attribut [Required] sur un paramètre d'opération pour forcer une valeur non nulle / non vide.&lt;/p&gt;

&lt;p&gt;Bien sûr, rien ne nous empêche de créer des validateurs pour des types complexes, et s'en servir pour valider des entités métier...&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Voilà donc une solution élégante pour la validation des paramètres d'entrée d'un service WCF.&lt;/p&gt;

&lt;p&gt;Les sources de l'exemple sont disponibles &lt;a href="http://www.simonferquel.net/blog/WCFInputValidation.zip"&gt;ici&lt;/a&gt;.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:5801ddaa-0f0d-4dfb-b250-6a9ce5addc31" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Mots clés Technorati : &lt;a href="http://technorati.com/tags/WCF" rel="tag"&gt;WCF&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SOA" rel="tag"&gt;SOA&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Validation" rel="tag"&gt;Validation&lt;/a&gt;,&lt;a href="http://technorati.com/tags/CSharp" rel="tag"&gt;CSharp&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/44.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=kxYkU47ZWiw:EcplLdN7JY4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=kxYkU47ZWiw:EcplLdN7JY4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=kxYkU47ZWiw:EcplLdN7JY4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=kxYkU47ZWiw:EcplLdN7JY4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=kxYkU47ZWiw:EcplLdN7JY4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/kxYkU47ZWiw" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/01/17/wcf-validation-des-entreacutees.aspx</guid>
            <pubDate>Sat, 17 Jan 2009 17:37:38 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/44.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/01/17/wcf-validation-des-entreacutees.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/44.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/44.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/01/17/wcf-validation-des-entreacutees.aspx</feedburner:origLink></item>
        <item>
            <title>Techdays 2009, c'est pour bient&amp;ocirc;t</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/sdBHwv6On7A/techdays-2009-cest-pour-bientocirct.aspx</link>
            <description>&lt;p&gt;Les &lt;a href="http://www.microsoft.com/france/mstechdays/"&gt;Techdays 2009&lt;/a&gt; vont avoir lieu du mardi 10 février au jeudi 12 février prochain à Paris au palais des congrès de Paris. Ce sera l'occasion pour moi de vous faire partager mon expérience sur Silverlight au sein de 2 sessions co-animées avec &lt;a href="http://blogs.msdn.com/pierlag"&gt;Pierre Lagarde&lt;/a&gt; (MS France) et &lt;a href="http://www.ucaya.com/blog/"&gt;Thierry Bouquain&lt;/a&gt; (Ucaya), tous les deux contributeurs du projet &lt;a href="http://www.codeplex.com/SLExtensions"&gt;Silverlight Extensions&lt;/a&gt; (&lt;a href="http://galilee.microsoft.fr/TechDays2009/Session.aspx?CellID=d5ad9c8c-bb16-4be1-a781-b826cba72966"&gt;Développement avancé avec Silverlight 2&lt;/a&gt;, et &lt;a href="1214a3dc-10fa-4d82-b4c8-1ca8685e52b9"&gt;Développement de contrôles en Silverlight 2&lt;/a&gt;) , ainsi que de m'essayer à quelques exercices de style avec &lt;a href="http://blogs.msdn.com/mitsufu"&gt;Mitsuru Furuta&lt;/a&gt; dans une session pompeusement appelée &lt;a href="http://galilee.microsoft.fr/TechDays2009/Session.aspx?CellID=490a4112-6a60-403d-9e86-9ada349529b1"&gt;Programmation dynamique&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Bref, quelques journées de préparation en perspective (et quelques mojitos aussi vu les gus avec qui je co-anime tout ca !).&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:35cffe79-91d3-4853-839f-94d2f09efe22" class="wlWriterSmartContent"&gt;Mots clés Technorati : &lt;a href="http://technorati.com/tags/Microsoft" rel="tag"&gt;Microsoft&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Techdays" rel="tag"&gt;Techdays&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Silverlight" rel="tag"&gt;Silverlight&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/43.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=sdBHwv6On7A:QkuJpKRWYPA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=sdBHwv6On7A:QkuJpKRWYPA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=sdBHwv6On7A:QkuJpKRWYPA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=sdBHwv6On7A:QkuJpKRWYPA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=sdBHwv6On7A:QkuJpKRWYPA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/sdBHwv6On7A" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/01/12/techdays-2009-cest-pour-bientocirct.aspx</guid>
            <pubDate>Mon, 12 Jan 2009 20:42:59 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/43.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/01/12/techdays-2009-cest-pour-bientocirct.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/43.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/43.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/01/12/techdays-2009-cest-pour-bientocirct.aspx</feedburner:origLink></item>
        <item>
            <title>MVPed !</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/SvFmBCJypiI/mvped.aspx</link>
            <description>&lt;p&gt;Voilà un année qui commence bien, je viens de recevoir ma nomination de MVP "Client App" dev ! Merci à Microsoft et plus particulièrement à Mitsu et aux developper evangelysts de MS France DPE pour m'avoir appuyé :-).&lt;/p&gt;  &lt;p&gt;A bientôt, Simon&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/42.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=SvFmBCJypiI:s4kcR4MpsAA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=SvFmBCJypiI:s4kcR4MpsAA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=SvFmBCJypiI:s4kcR4MpsAA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=SvFmBCJypiI:s4kcR4MpsAA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=SvFmBCJypiI:s4kcR4MpsAA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/SvFmBCJypiI" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/01/01/mvped.aspx</guid>
            <pubDate>Thu, 01 Jan 2009 16:48:56 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/42.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/01/01/mvped.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/42.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/42.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/01/01/mvped.aspx</feedburner:origLink></item>
        <item>
            <title>[Silverlight 2] Molette de la souris, solution non intrusive</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/vWrS_XU9anw/silverlight-2-molette-de-la-souris-solution-non-intrusive.aspx</link>
            <description>&lt;p&gt;Nativement, Silverlight ne prend en compte qu'un nombre limité d'évènements souris :&lt;/p&gt; &lt;ul&gt; &lt;li&gt;MouseMove / Enter/ Leave&lt;/li&gt; &lt;li&gt;MouseLeftButtonDown / Up&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Or, dans beaucoup d'applications métiers, certains écrans font apparaître des scrollbars (vue complexe, ListBox, ComboBox, DataGrid...). A la vue de ces scrollbars, l'utilisateur lambda a très souvent le réflexe d'utiliser sa souris pour faire défiler les éléments de haut en bas. Hors Silverlight ne supporte pas ces évènements et les Controles ScrollViewer, DataGrid etc. ne supportent donc pas nativement la molette.&lt;/p&gt; &lt;p&gt;Si vous avez déjà joué avec le Scrolling "programmatique", vous avez peut-être remarqué que beaucoup de contrôles faisant apparaître une ScrollBar n'utilisent pas de ScrollViewer, mais ont leur propre logique de Scrolling (bien souvent non exposée publiquement - c'est le cas notamment du DataGrid) pour diverses raisons (Virtualisation des éléments...) et il ne semble donc pas possible d'avoir une solution "miracle" qui marche dans tous les cas.&lt;/p&gt; &lt;p&gt;L'astuce présentée ici s'appuie sur les fonctionnalités d'automatisation d'interface (voir namespace System.Windows.UIAutomation dans la doc MSDN). En effet, l'API d'automatisation de Microsoft propose un moyen d'exposer des fonctionnalités de Scrolling aux lecteurs / contrôleurs d'écrans et framework de test. Chaque contrôle ayant une logique de scrolling peut donc l'exposer via son AutomationPeer : c'est ce que font tous les contrôles de ce type de Silverlight core, Silverlight Toolkit, ainsi que ceux des auteurs de CustomControls consciencieux. Voici par exemple un extrait de code d'une SuggestBox supportant l'automation :&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SuggestBox &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Control
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;private class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SuggestBoxAutomationPeer &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;FrameworkElementAutomationPeer
        &lt;/span&gt;{
            &lt;span style="color: #2b91af"&gt;SuggestBox &lt;/span&gt;_automated;
            &lt;span style="color: blue"&gt;public &lt;/span&gt;SuggestBoxAutomationPeer(&lt;span style="color: #2b91af"&gt;SuggestBox &lt;/span&gt;automated)
                : &lt;span style="color: blue"&gt;base&lt;/span&gt;(automated)
            {
                _automated = automated;
            }

            &lt;span style="color: blue"&gt;public override object &lt;/span&gt;GetPattern(&lt;span style="color: #2b91af"&gt;PatternInterface &lt;/span&gt;patternInterface)
            {
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(patternInterface == &lt;span style="color: #2b91af"&gt;PatternInterface&lt;/span&gt;.Scroll)
                {
                    &lt;span style="color: blue"&gt;if &lt;/span&gt;(_automated.IsPopupOpen &amp;amp;&amp;amp; _automated._childListBox != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;FrameworkElementAutomationPeer&lt;/span&gt;.CreatePeerForElement(_automated._childListBox).GetPattern(patternInterface);
                }
                &lt;span style="color: blue"&gt;return base&lt;/span&gt;.GetPattern(patternInterface);
            }
        }
        &lt;span style="color: blue"&gt;protected override &lt;/span&gt;System.Windows.Automation.Peers.&lt;span style="color: #2b91af"&gt;AutomationPeer &lt;/span&gt;OnCreateAutomationPeer()
        {
            &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SuggestBoxAutomationPeer&lt;/span&gt;(&lt;span style="color: blue"&gt;this&lt;/span&gt;);
        }
    }&lt;/pre&gt;&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;p&gt;Pour exploiter celà, la première chose à faire, est d'implémenter notre scrolling programmatique a un endroit centralisé, qui sera appelable par JavaScript. Dans cet exemple, nous prendrons l'objet Application lui-même. Nous aurons besoin simplement d'une méthode marquée [ScriptableMember] et d'enregistrer l'objet application comme un ScriptableObject:&lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;UIElement&lt;/span&gt;&amp;gt; SelfAndAncestors(&lt;span style="color: #2b91af"&gt;UIElement &lt;/span&gt;source)
        {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;current = source;
            &lt;span style="color: blue"&gt;do
            &lt;/span&gt;{
                &lt;span style="color: blue"&gt;yield return &lt;/span&gt;current;
                current = &lt;span style="color: #2b91af"&gt;VisualTreeHelper&lt;/span&gt;.GetParent(current) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UIElement&lt;/span&gt;;
            }
            &lt;span style="color: blue"&gt;while &lt;/span&gt;(current != &lt;span style="color: blue"&gt;null&lt;/span&gt;);
        }

        [&lt;span style="color: #2b91af"&gt;ScriptableMember&lt;/span&gt;]
        &lt;span style="color: blue"&gt;public void &lt;/span&gt;OnMouseWheel(&lt;span style="color: blue"&gt;double &lt;/span&gt;delta)
        {          

            &lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;UIElement&lt;/span&gt;&amp;gt; candidates;
            
            candidates = &lt;span style="color: #2b91af"&gt;VisualTreeHelper&lt;/span&gt;.FindElementsInHostCoordinates(_currentMousePosition, RootVisual);
            &lt;span style="color: green"&gt;// Si un element a le focus, on gere les candidats 
            // en placant en premier l'élément ayant le focus ainsi que ses parents
            &lt;/span&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;focused = &lt;span style="color: #2b91af"&gt;FocusManager&lt;/span&gt;.GetFocusedElement() &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;UIElement&lt;/span&gt;;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(focused != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                candidates = SelfAndAncestors(focused)
                    .Concat(candidates);
            &lt;span style="color: blue"&gt;var &lt;/span&gt;scrollProvider = (&lt;span style="color: blue"&gt;from &lt;/span&gt;elem &lt;span style="color: blue"&gt;in &lt;/span&gt;candidates
                                  &lt;span style="color: blue"&gt;let &lt;/span&gt;automationPeer = &lt;span style="color: #2b91af"&gt;FrameworkElementAutomationPeer&lt;/span&gt;.CreatePeerForElement(elem)
                                  &lt;span style="color: blue"&gt;where &lt;/span&gt;automationPeer != &lt;span style="color: blue"&gt;null
                                  let &lt;/span&gt;scroller = automationPeer.GetPattern(&lt;span style="color: #2b91af"&gt;PatternInterface&lt;/span&gt;.Scroll) &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IScrollProvider
                                  &lt;/span&gt;&lt;span style="color: blue"&gt;where &lt;/span&gt;scroller != &lt;span style="color: blue"&gt;null
                                  select &lt;/span&gt;scroller).FirstOrDefault();

            &lt;span style="color: blue"&gt;if &lt;/span&gt;(scrollProvider != &lt;span style="color: blue"&gt;null &lt;/span&gt;&amp;amp;&amp;amp; scrollProvider.VerticallyScrollable)
            {

                &lt;span style="color: blue"&gt;if &lt;/span&gt;(delta &amp;gt; 0)
                    scrollProvider.Scroll(System.Windows.Automation.&lt;span style="color: #2b91af"&gt;ScrollAmount&lt;/span&gt;.NoAmount,
                        System.Windows.Automation.&lt;span style="color: #2b91af"&gt;ScrollAmount&lt;/span&gt;.SmallDecrement);
                &lt;span style="color: blue"&gt;else
                    &lt;/span&gt;scrollProvider.Scroll(System.Windows.Automation.&lt;span style="color: #2b91af"&gt;ScrollAmount&lt;/span&gt;.NoAmount,
                        System.Windows.Automation.&lt;span style="color: #2b91af"&gt;ScrollAmount&lt;/span&gt;.SmallIncrement);
            }
            
        }&lt;/pre&gt;&lt;pre class="code"&gt;&lt;font face="Trebuchet MS"&gt;Le &lt;/font&gt;&lt;font face="Trebuchet MS"&gt;paramêtre delta aura pour valeur le delta de l'évènement JavaScript MouseWheel intercepté. &lt;/font&gt;&lt;/pre&gt;
&lt;p&gt;&lt;font face="Trebuchet MS"&gt;La partie la plus importante de la méthode est la requête Linq qui parcoure la liste des candidats (liste d'UIElement produient par &lt;span style="color: #2b91af"&gt;VisualTreeHelper&lt;/span&gt;.FindElementsInHostCoordinates et par le FocusManager. Ce que l'on recherche, c'est le premier UIElement ayant un automationPeer supportant le scrolling. Une foit qu'on l'a trouvé, on manipule simplement le scrollProvider pour lui indiquer ce que l'on souhaite faire. Cette méthode fonctionne aussi bien avec les ScrollViewer, DataGrid, ListBox, SuggestBox etc, bien que leur logique de scrolling soit différente (et souvent inaccessible publiquement).&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Il ne reste plus qu'à brancher ce code sur un évènement JavaScript.&lt;/p&gt;
&lt;p&gt;D'abord, nous enregistrons l'objet application dans le dictionnaire d'objet Scriptable dans la méthode Application_Startup():&lt;/p&gt;
&lt;p&gt;HtmlPage.RegisterScriptableObject("SilverlightApp", this);
&lt;/p&gt;&lt;p&gt;Ensuite dans la page HTML hôte de notre application, nous effectuons les tâches suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modification du tag object:&lt;/li&gt;&lt;/ul&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="silverlightControlHost"&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;object &lt;/span&gt;&lt;span style="color: red"&gt;data&lt;/span&gt;&lt;span style="color: blue"&gt;="data:application/x-silverlight-2," &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;="application/x-silverlight-2" &lt;/span&gt;&lt;span style="color: red"&gt;width&lt;/span&gt;&lt;span style="color: blue"&gt;="100%" &lt;/span&gt;&lt;span style="color: red"&gt;height&lt;/span&gt;&lt;span style="color: blue"&gt;="100%"&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;            ...&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;param &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;="onload" &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;="onSilverlightLoad" /&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;="http://go.microsoft.com/fwlink/?LinkID=124807" &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;="&lt;/span&gt;&lt;span style="color: red"&gt;text-decoration&lt;/span&gt;: &lt;span style="color: blue"&gt;none&lt;/span&gt;;&lt;span style="color: blue"&gt;"&amp;gt;
                 &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;img &lt;/span&gt;&lt;span style="color: red"&gt;src&lt;/span&gt;&lt;span style="color: blue"&gt;="http://go.microsoft.com/fwlink/?LinkId=108181" &lt;/span&gt;&lt;span style="color: red"&gt;alt&lt;/span&gt;&lt;span style="color: blue"&gt;="Get Microsoft Silverlight" &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;="&lt;/span&gt;&lt;span style="color: red"&gt;border-style&lt;/span&gt;: &lt;span style="color: blue"&gt;none"/&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;object&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;iframe &lt;/span&gt;&lt;span style="color: red"&gt;style&lt;/span&gt;&lt;span style="color: blue"&gt;='&lt;/span&gt;&lt;span style="color: red"&gt;visibility&lt;/span&gt;:&lt;span style="color: blue"&gt;hidden&lt;/span&gt;;&lt;span style="color: red"&gt;height&lt;/span&gt;:&lt;span style="color: blue"&gt;0&lt;/span&gt;;&lt;span style="color: red"&gt;width&lt;/span&gt;:&lt;span style="color: blue"&gt;0&lt;/span&gt;;&lt;span style="color: red"&gt;border&lt;/span&gt;:&lt;span style="color: blue"&gt;0px'&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;iframe&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;div&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Ce qu'il faut rajouter, c'est le tag &amp;lt;param name="onload" /&amp;gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implémenter la fonction onSilverlightLoad:&lt;/li&gt;&lt;/ul&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;slApp;
        &lt;span style="color: green"&gt;/** This is high-level function.
        * It must react to delta being more/less than zero.
        */
        &lt;/span&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;handle(delta) {
            slApp.OnMouseWheel(delta);
        }

        &lt;span style="color: green"&gt;/** Event handler for mouse wheel event.
        */
        &lt;/span&gt;&lt;span style="color: blue"&gt;function &lt;/span&gt;wheel(event) {
            &lt;span style="color: blue"&gt;var &lt;/span&gt;delta = 0;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(!event) &lt;span style="color: green"&gt;/* For IE. */
                &lt;/span&gt;event = window.event;
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(event.wheelDelta) { &lt;span style="color: green"&gt;/* IE/Opera. */
                &lt;/span&gt;delta = event.wheelDelta / 120;
                &lt;span style="color: green"&gt;/** In Opera 9, delta differs in sign as compared to IE.
                */
                &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(window.opera)
                    delta = -delta;
            } &lt;span style="color: blue"&gt;else if &lt;/span&gt;(event.detail) { &lt;span style="color: green"&gt;/** Mozilla case. */
                /** In Mozilla, sign of delta is different than in IE.
                * Also, delta is multiple of 3.
                */
                &lt;/span&gt;delta = -event.detail / 3;
            }
            &lt;span style="color: green"&gt;/** If delta is nonzero, handle it.
            * Basically, delta is now positive if wheel was scrolled up,
            * and negative, if wheel was scrolled down.
            */
            &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(delta)
                handle(delta);
            &lt;span style="color: green"&gt;/** Prevent default actions caused by mouse wheel.
            * That might be ugly, but we handle scrolls somehow
            * anyway, so don't bother here..
            */
            &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(event.preventDefault)
                event.preventDefault();
            event.returnValue = &lt;span style="color: blue"&gt;false&lt;/span&gt;;
        }



        &lt;span style="color: blue"&gt;function &lt;/span&gt;onSilverlightLoad(sender, args) {

            &lt;span style="color: blue"&gt;var &lt;/span&gt;slCtl = sender.getHost();
            slApp = slCtl.Content.SilverlightApp;
            &lt;span style="color: green"&gt;/** Initialization code. 
            * If you use your own event management code, change it as required.
            */
            &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(window.addEventListener)
            &lt;span style="color: green"&gt;/** DOMMouseScroll is for mozilla. */
                &lt;/span&gt;window.addEventListener(&lt;span style="color: #a31515"&gt;'DOMMouseScroll'&lt;/span&gt;, wheel, &lt;span style="color: blue"&gt;false&lt;/span&gt;);
            &lt;span style="color: green"&gt;/** IE/Opera. */
            &lt;/span&gt;window.onmousewheel = document.onmousewheel = wheel;

        }&lt;/pre&gt;Et voilà, that's done :).&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/41.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=vWrS_XU9anw:_A-UaFJ-j1s:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=vWrS_XU9anw:_A-UaFJ-j1s:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=vWrS_XU9anw:_A-UaFJ-j1s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=vWrS_XU9anw:_A-UaFJ-j1s:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=vWrS_XU9anw:_A-UaFJ-j1s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Simonferquelnet/~4/vWrS_XU9anw" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2008/12/31/silverlight-2-molette-de-la-souris-solution-non-intrusive.aspx</guid>
            <pubDate>Wed, 31 Dec 2008 11:54:32 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/41.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2008/12/31/silverlight-2-molette-de-la-souris-solution-non-intrusive.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/41.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/41.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2008/12/31/silverlight-2-molette-de-la-souris-solution-non-intrusive.aspx</feedburner:origLink></item>
    </channel>
</rss>
