<?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" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
            <title>[Debug] Events et MemoryLeaks</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/9qPNgq0AD_k/debug-events-et-memoryleaks.aspx</link>
            <description>&lt;p&gt;Une des plus grandes sources de MemoryLeaks dans les applications .Net (en particulier dans le cas d’applications Windows Forms, WPF et Silverlight), sont la création d’event handlers sur des events exposés par des objets ayant un temps de vie long, ou sur des events statiques (typiquement un évènement de la classe Microsoft.Win32.SystemEvents, ou un évènement exposé par un singleton – oui je sais, les puristes de la POO qui vont lire cette phrase vont vomir).&lt;/p&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt;La raison est très simple : quand on crée un délégué (EventHandler ou autre), celui-ci possède une référence forte sur l’objet qui prend en charge l’évènement. De plus, quand on ajoute un délégué à un évènement (typiquement MonObjetSource.MonEvent += monEventHandler), cet évènement a une référence forte au délégué. Du coup, tant que l’on ne se désabonne pas, l’objet prenant en charge l’évènement reste référencé, et si la source de l’évènement n’est pas elle-même déréférencée (ce qui n’est jamais le cas avec des events statiques par exemple), l’objet prenant en charge l’évènement ne sera jamais collecté par le Garbage Collector : et on a un jouli potentiel memory leak (les puristes appellent ca plutôt un Handle Leak, parce que la source du problème n’est pas un oublie de désallocation de mémoire, mais un oublie de déréférencement).&lt;/p&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt;Le cas typique, c’est un composant qui s’abonne à un évènement système, mais qui ne se désabonne jamais. Potentiellement à cause d’un oubli d’appel à une méthode Dispose ou quelque chose dans le genre. Un autre cas courrant, c’est le controlleur (ou le ViewModel) d’une vue qui s’abonne à un évènement d’un objet métier à longue durée de vie, et qui ne s’y désabonne pas (en Silverlight, c’est d’ailleurs très compliqué de se désabonner d’un évènement quand un contrôle sort de l’arbre visuel, car on n’a pas d’évènement UnLoad).&lt;/p&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt;Comment faire face à ce problème (pas super simple à debugger pour courroner le tout, souvent incompris par les développeurs novices, et encore plus souvent détecté par le client qui se plaint d’une consommation mémoire désastreuse, à qui souvent les développeurs disent “ca peut pas venir de nous, nous on gère pas la mémoire, c’est le Garbage Collector qui sait”, et qui du coup s’en va propager la nouvelle comme quoi franchement, les Applis .Net c’est super lourd, faut 40 go de RAM pour les faire tourner, et au bout de 16 heures d’activité, ca fait systématiquement une OutOfMemoryException) ? Il existe plusieurs possibilités (liste pas forcément exhaustive) :&lt;/p&gt; &lt;p&gt; &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Toujours, toujours, TOUJOURS se désabonner à un évènement auquel on s’est attaché, sauf pour :  &lt;ul&gt; &lt;li&gt;Les évènements des contrôles si et seulement si ils sont pris en charge par le UserControl ou le formulaire qui les a créés (et qui les contient)  &lt;/li&gt;&lt;li&gt;Si l’objet qui prend en charge l’évènement est lui même un singleton (oui je sais les puristes, le singleton c’est pas bon) &lt;/li&gt;&lt;/ul&gt; &lt;/li&gt;&lt;li&gt;Utiliser le WeakEventManager / WeakEvents pattern (mais c’est pas disponible sous Silverlight, et en plus c’est compliqué)  &lt;/li&gt;&lt;li&gt;Créer un objet WeakEventHandler qui servira de proxy entre l’évènement et sa cible (l’idée est de référencer la cible uniquement via une WeakReference). &lt;/li&gt;&lt;/ul&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt;Le problème de cette dernière solution (la seule possible dans certains cas avec Silverlight), c’est que la classe WeakEventHandler est compliquée à implémenter, et peut potentiellement cacher un nouveau leak. Je vous donne donc ici, mon implémentation de référence, ainsi qu’un code snippet permettant de générer des WeakEventHandlers spécifiques à un évènement donné. L’idée étant d’avoir au final une utilisation aussi simple que :&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedWeakEventHandler&lt;/span&gt;.Initialize(&lt;span style="color: blue"&gt;this&lt;/span&gt;, EventSource,
    (target,s, a)=&amp;gt;target.Messages.Add(a.PropertyName+ &lt;span style="color: #a31515"&gt;" changed"&lt;/span&gt;));&lt;/pre&gt;&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;p&gt;La méthode initialize prend 3 paramètres : la cible de l’évènement (qui sera encapsulée dans une WeakReference), l’objet source de l’évènement PropertyChanged, et un délégués statiques (qui n’a donc pas de référence à l’objet courrant et ne provoquera pas de leak). Ce dernier paramètre est vérifié à l’exécution en regardant si sa propriété Target est non nulle. Le délégué obtiendra une référence à l’objet cible grace à son premier paramètre.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Le code derrière cette classe est assez complexe, il repose lui même sur une classe générique abstraite que j’utilisais précédement directement, mais qui demandait un peu plus de plomberie, et était du coup beaucoup plus susceptible de provoquer des bugs.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Du coup, je vous file juste les sources contenant tout ce qu’il faut pour prendre en charge les évènements PropertyChanged, ainsi qu’un code Snippet permettant de créer vos propres WeakEventHandlers spécifiques (pour CollectionChanged, SystemEvents etc.) sans avoir à comprendre comment fonctionne la classe de base (allez, petit spoiler quand même, elle a 4 paramètres génériques, et fait largement partie des bouts de codes les moins lisibles que j’ai peu produire) : &lt;a href="http://www.simonferquel.net/blog/SStuff.Events.zip"&gt;SStuff.Events.zip&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/57.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=9qPNgq0AD_k:SmEbSMP0p4o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=9qPNgq0AD_k:SmEbSMP0p4o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=9qPNgq0AD_k:SmEbSMP0p4o: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=9qPNgq0AD_k:SmEbSMP0p4o: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=9qPNgq0AD_k:SmEbSMP0p4o: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=9qPNgq0AD_k:SmEbSMP0p4o: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/9qPNgq0AD_k" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/10/30/debug-events-et-memoryleaks.aspx</guid>
            <pubDate>Fri, 30 Oct 2009 09:21:44 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/57.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/10/30/debug-events-et-memoryleaks.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/57.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/57.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/10/30/debug-events-et-memoryleaks.aspx</feedburner:origLink></item>
        <item>
            <title>Co/Contra Variance : une nouveaut&amp;eacute; pas si nouvelle</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/_cOxpfVERBw/cocontra-variance--une-nouveauteacute-pas-si-nouvelle.aspx</link>
            <description>&lt;p&gt;C# 4.0 introduit une nouveauté très intéressante au niveau des déclarations d’interfaces / délégués génériques : la notion de Co-variance et Contra-variance.&lt;/p&gt;  &lt;p&gt;La co-variance permet de dire que si un type implémente IMonInterface&amp;lt;TypeDérivé&amp;gt;, il implémente aussi IMonInterface&amp;lt;TypeParent&amp;gt;. &lt;/p&gt;  &lt;p&gt;Pour la contra-variance, c’est exactement le contraire.&lt;/p&gt;  &lt;p&gt;Du coup, les développeurs de la BCL ont modifié la déclaration de pas mal d’interfaces et délégués génériques pour profiter de ces règles : ainsi tout IEnumerable&amp;lt;string&amp;gt; implémente automatiquement IEnumerable&amp;lt;object&amp;gt; et tout délégué de type Action&amp;lt;object&amp;gt; peut être utilisé à la place d’un Action&amp;lt;string&amp;gt;.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;En fait cette notion de co-variance / contra-variance, bien que non déclarable en C# et VB dans leur versions actuelle est présente dans les spécifications du langage MSIL depuis .Net 2.0, et si l’on en a le courage, on peut tout a fait créer des interfaces / délégués co/contra-variants. Pour ceci, il faut simplement indiquer un “+” (co-variant) ou un “-“ (contra-variant) devant le paramètre du type. Voici un exemple avec 2 interfaces définie en MSIL :&lt;/p&gt;  &lt;pre class="code"&gt;.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) 
  .ver 2:0:0:0
}
.assembly Cotypes
{
  .ver 0:0:0:0
}
.module Cotypes.dll


// +T indique que l'interface est CoVariante (toute implementation de IValueProvider&amp;lt;ChildClass&amp;gt;&lt;br /&gt;// implemente IValueProvider&amp;lt;ParentClass&amp;gt;)
.class interface public abstract auto ansi Cotypes.IValueProvider`1&amp;lt;+T&amp;gt;
{
  .method public hidebysig newslot abstract virtual 
          instance !T  GetValue() cil managed
  {
  } 
} 

// -T indique que l'interface est ContraVariante (toute implementation de IValueConsumer&amp;lt;ParentClass&amp;gt;&lt;br /&gt;// implemente IValueConsumer&amp;lt;ChildClass&amp;gt;)
.class interface public abstract auto ansi Cotypes.IValueConsumer`1&amp;lt;-T&amp;gt;
{
  .method public hidebysig newslot abstract virtual 
          instance void  SetValue(!T 'value') cil managed
  {
  } 

}&lt;/pre&gt;

&lt;p&gt;Une fois compilée sous forme de DLL, on peut alors implémenter ces interfaces en C# et profiter la co/contra-variance :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;static void &lt;/span&gt;Main(&lt;span style="color: blue"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color: #2b91af"&gt;IValueProvider&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; stringProvider = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;StringValueProvider&lt;/span&gt;(&lt;span style="color: #a31515"&gt;"HelloWorld"&lt;/span&gt;);
    &lt;span style="color: #2b91af"&gt;IValueProvider&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt; objProvider = stringProvider &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IValueProvider&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt;;

    &lt;span style="color: #2b91af"&gt;IValueConsumer&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt; objConsumer = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ConsoleDisplayer&lt;/span&gt;();
    &lt;span style="color: #2b91af"&gt;IValueConsumer&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; stringConsumer = objConsumer &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IValueConsumer&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;;

    objConsumer.SetValue(objProvider.GetValue());
    stringConsumer.SetValue(stringProvider.GetValue());
}&lt;/pre&gt;

&lt;p&gt;En C# 4.0, la seule différence (en dehors du fait que l’écriture de telles interfaces peut se faire directement en C#) est qu’il n’y a pas besoin du mot-clef as, l’opération de cast se fait implicitement.&lt;/p&gt;

&lt;p&gt;Vous pouvez télécharger les sources de cet exemple &lt;a href="http://www.simonferquel.net/blog/DemoCovariance.zip"&gt;ici&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/56.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=_cOxpfVERBw:BTBVi48Ex2w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=_cOxpfVERBw:BTBVi48Ex2w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=_cOxpfVERBw:BTBVi48Ex2w: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=_cOxpfVERBw:BTBVi48Ex2w: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=_cOxpfVERBw:BTBVi48Ex2w: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=_cOxpfVERBw:BTBVi48Ex2w: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/_cOxpfVERBw" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/10/09/cocontra-variance--une-nouveauteacute-pas-si-nouvelle.aspx</guid>
            <pubDate>Fri, 09 Oct 2009 11:03:07 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/56.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/10/09/cocontra-variance--une-nouveauteacute-pas-si-nouvelle.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/56.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/56.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/10/09/cocontra-variance--une-nouveauteacute-pas-si-nouvelle.aspx</feedburner:origLink></item>
        <item>
            <title>INotifyPropertyChanged</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/oL7JptfgSUw/inotifypropertychanged.aspx</link>
            <description>&lt;p&gt;Lorsque l’on développe des applications avec WPF ou Silverlight, une des tâches les plus répétitives et les plus propices aux erreurs est l’implémentation de INotifyPropertyChanged et la génération d’évènements lors de l’affectation d’une propriété sur nos objets source de DataBinding. Voici par exemple une classe Customer implémentant INotifyPropertyChanged d’une manière classique :&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;Customer &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;INotifyPropertyChanged
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public event &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler &lt;/span&gt;PropertyChanged;
    &lt;span style="color: blue"&gt;protected void &lt;/span&gt;OnPropertyChanged(&lt;span style="color: blue"&gt;string &lt;/span&gt;propertyName)
    {
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(PropertyChanged != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            PropertyChanged(&lt;span style="color: blue"&gt;this&lt;/span&gt;, &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventArgs&lt;/span&gt;(propertyName));
    }

    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_firstName;
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;FirstName
    {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_firstName; }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(_firstName != &lt;span style="color: blue"&gt;value&lt;/span&gt;)
            {
                _firstName = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
                OnPropertyChanged(&lt;span style="color: #a31515"&gt;"FirstName"&lt;/span&gt;);
            }
        }
    }

    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_lastName;
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;LastName
    {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_lastName; }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(_lastName != &lt;span style="color: blue"&gt;value&lt;/span&gt;)
            {
                _lastName = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
                OnPropertyChanged(&lt;span style="color: #a31515"&gt;"LastName"&lt;/span&gt;);
            }
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Ce code illustre très bien deux problèmes :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;C’est très verbeux &lt;/li&gt;

  &lt;li&gt;Une faute de frappe dans la chaine de caractères passée à la méthode OnPropertyChanged est vite arrivée (ca m’est d’ailleurs arrivé pendant l’écriture de cet article, car je switch pas mal entre clavier Azerty et Qwerty) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Je reviendrai un peu plus tard sur le premier problème, pour l’instant nous allons nous concentrer sur le second qui est pour moi le plus critique. En plus du risque de faute de frappe, il expose aussi le développeur à des erreurs possibles lors d’un potentiel Refactoring. Pour rendre ce code plus sûr et vérifié à la compilation, il existe plusieurs alternatives :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Utiliser un composant ObservableObject (voir &lt;a title="http://compositewpf.codeplex.com/" href="http://compositewpf.codeplex.com/"&gt;http://compositewpf.codeplex.com/&lt;/a&gt;) qui encapsule l’implémentation d’INotifyPropertyChanged via une classe séparée : cette solution est séduisante à première vue mais conduit à un nombre peu commode d’indirections lorsque l’on veut accéder à une valeur (monCustomer.FirstName=”toto” devient monCustomer.FirstName.Value = “toto”) &lt;/li&gt;

  &lt;li&gt;Utiliser la reflection pour récupérer le nom de la propriété courrante : 
    &lt;br /&gt;

    &lt;blockquote style="margin-right: 0px" dir="ltr"&gt;
      &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Customer &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;INotifyPropertyChanged
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public event &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler &lt;/span&gt;PropertyChanged;
    &lt;span style="color: blue"&gt;protected void &lt;/span&gt;OnPropertyChanged(&lt;span style="color: blue"&gt;string &lt;/span&gt;propertyName)
    {
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(PropertyChanged != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            PropertyChanged(&lt;span style="color: blue"&gt;this&lt;/span&gt;, &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventArgs&lt;/span&gt;(propertyName));
    }

    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_firstName;
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;FirstName
    {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_firstName; }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(_firstName != &lt;span style="color: blue"&gt;value&lt;/span&gt;)
            {
                _firstName = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
               
                OnPropertyChanged( &lt;span style="color: #2b91af"&gt;MethodInfo&lt;/span&gt;.GetCurrentMethod()
                    .Name.Substring(4));
            }
        }
    }

    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_lastName;
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;LastName
    {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_lastName; }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(_lastName != &lt;span style="color: blue"&gt;value&lt;/span&gt;)
            {
                _lastName = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
                OnPropertyChanged( &lt;span style="color: #2b91af"&gt;MethodInfo&lt;/span&gt;.GetCurrentMethod()
                    .Name.Substring(4));
            }
        }
    }
}&lt;/pre&gt;
    &lt;/blockquote&gt;
Cette solution est originale, mais faire appel aux API d’introspection à chaque affectation de propriété a un impact très négatif sur les performances &lt;/li&gt;

  &lt;li&gt;Ma solution préférée : passer par des arbres d’expression Linq en modifiant légèrement la signature de OnPropertyChanged :&lt;/li&gt;
&lt;/ul&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;using &lt;/span&gt;System.Linq;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.ComponentModel;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Reflection;
&lt;span style="color: blue"&gt;using &lt;/span&gt;System.Linq.Expressions;

&lt;span style="color: blue"&gt;namespace &lt;/span&gt;SStuff.NotifySample
{
    &lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Customer &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;INotifyPropertyChanged
    &lt;/span&gt;{
        &lt;span style="color: blue"&gt;public event &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler &lt;/span&gt;PropertyChanged;
        &lt;span style="color: blue"&gt;protected void &lt;/span&gt;OnPropertyChanged&amp;lt;T&amp;gt;(&lt;span style="color: #2b91af"&gt;Expression&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;T&amp;gt;&amp;gt; propAccess)
        {
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(PropertyChanged != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
            {
                &lt;span style="color: blue"&gt;var &lt;/span&gt;asMember = propAccess.Body &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MemberExpression&lt;/span&gt;;
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(asMember == &lt;span style="color: blue"&gt;null&lt;/span&gt;)
                    &lt;span style="color: blue"&gt;return&lt;/span&gt;;

                PropertyChanged(&lt;span style="color: blue"&gt;this&lt;/span&gt;, &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventArgs&lt;/span&gt;(asMember.Member.Name));
            }
        }

        &lt;span style="color: blue"&gt;private string &lt;/span&gt;_firstName;
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;FirstName
        {
            &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_firstName; }
            &lt;span style="color: blue"&gt;set
            &lt;/span&gt;{
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(_firstName != &lt;span style="color: blue"&gt;value&lt;/span&gt;)
                {
                    _firstName = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
                   
                    OnPropertyChanged( ()=&amp;gt;FirstName);
                }
            }
        }

        &lt;span style="color: blue"&gt;private string &lt;/span&gt;_lastName;
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;LastName
        {
            &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_lastName; }
            &lt;span style="color: blue"&gt;set
            &lt;/span&gt;{
                &lt;span style="color: blue"&gt;if &lt;/span&gt;(_lastName != &lt;span style="color: blue"&gt;value&lt;/span&gt;)
                {
                    _lastName = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
                    OnPropertyChanged( ()=&amp;gt; LastName);
                }
            }
        }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Cette solution a l’avantage d’être TypeSafe, relativement concise et plus lisible que la version basée sur la Reflection, et l’impact du parcours d’arbre d’expression sur les performances est censé être relativement réduit.&lt;/p&gt;

&lt;p&gt;Cela dit, toutes ces solutions ont en commun le fait de ne pas résoudre mon premier problème : ce code est très verbeux. A l’occasion des derniers Mecredis du Developpement (du jeudi) j’ai imaginé une solution qui me parait bien plus élégante : depuis quelques temps j’aborde tous mes développements d’applications WPF / Silverlight en utilisant le framework d’injection de dépendances Unity. Cela me permet entre autres d’isoler mes différents ViewModel afin de pouvoir les tester unitairement, et de créer des implémentations additionnelles spécifiques au DesignTime. En combinant injection de dépendance et création de types dynamiques (en utilisant Reflection.Emit), on peut ainsi retarder l’implémentation d’INotifyPropertyChanged à l’exécution ! Avec bien sûr un surcoup au démarrage (le temps de générer l’IL correspondant aux types dynamiques) qui est compensé ensuite par des performances tout à fait satisfaisantes, et une beaucoup plus grande pureté du code :&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;Customer
&lt;/span&gt;{
    [&lt;span style="color: #2b91af"&gt;Notify&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;FirstName { &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;Notify&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;LastName { &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Pour enregistrer ensuite le type dans Unity, le code est ensuite ultra-simple (grâce aux méthodes d’extension):&lt;/p&gt;

&lt;pre class="code"&gt;container
    .RegisterType(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;), 
                  &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;).AsNotify(&lt;span style="color: blue"&gt;null&lt;/span&gt;));&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;La méthode d’extension AsNotify génère un type hérité de Customer dynamiquement implémentant INotifyPropertyChanged correctement. Le paramètre optionel permet de fournir un MethodInfo au cas où une méthode OnPropertyChanged existerait déjà sur le type de base.&lt;/p&gt;

&lt;p&gt;Pour créer une instance de mon Customer dynamique, je passe alors pars Unity : container.Resolve&amp;lt;Customer&amp;gt;();&lt;/p&gt;

&lt;p&gt;Pour permettre des scénarios assez avancés avec l’injection de dépendance, tous les constructeurs de la classe de base sont reproduit dans le type dynamique, ainsi cette méthode s’intègre très bien dans une architecture MVVM avec injection de dépendances.&lt;/p&gt;

&lt;p&gt;Le code du NotifyTypeBuilder ainsi qu’un exemple MVVM avec Unity sont récupérable &lt;a href="http://www.simonferquel.net/blog/AutoNotify.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:333f85bd-7750-4d30-9493-1b90b2db6367" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/WPF" rel="tag"&gt;WPF&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Silverlight" rel="tag"&gt;Silverlight&lt;/a&gt;,&lt;a href="http://technorati.com/tags/MVVM" rel="tag"&gt;MVVM&lt;/a&gt;,&lt;a href="http://technorati.com/tags/INotifyPropertyChanged" rel="tag"&gt;INotifyPropertyChanged&lt;/a&gt;&lt;/div&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/54.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=oL7JptfgSUw:lQn8iQXaDAE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=oL7JptfgSUw:lQn8iQXaDAE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=oL7JptfgSUw:lQn8iQXaDAE: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=oL7JptfgSUw:lQn8iQXaDAE: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=oL7JptfgSUw:lQn8iQXaDAE: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=oL7JptfgSUw:lQn8iQXaDAE: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/oL7JptfgSUw" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/10/07/inotifypropertychanged.aspx</guid>
            <pubDate>Wed, 07 Oct 2009 12:58:26 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/54.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/10/07/inotifypropertychanged.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/54.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/54.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/10/07/inotifypropertychanged.aspx</feedburner:origLink></item>
        <item>
            <title>[Concurrency] Privatizable Shared state</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/GSZCGmnhQtw/concurrency-privatizable-shared-state.aspx</link>
            <description>&lt;p&gt;Le titre de ce post peut paraitre un peu obscur, mais il fait référence à une technique expliquée par &lt;a href="http://www.bluebytesoftware.com/blog/Default.aspx"&gt;Joe Duffy&lt;/a&gt; dans son livre Concurrent Programming on Windows (pour info, le monsieur est Lead developper et architecte sur PFX, il envoit sacrément du pâté et son bouquin est un must-read absolu pour tout développeur souhaitant garder son job dans les 5 ans à venir).&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;Un objet privatisable répond astucieusement à la problématique bien connue dans le développement de solutions multi-thread qu’est le partage d’un état en lecture-écriture. Le partage d’état connait deux contraintes importantes :&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;On doit se protéger des Race-conditions (multiples load-store en parallèle) &lt;/li&gt;    &lt;li&gt;Les modifications d’états composites doivent apparaître de manière atomique (l’objet doit apparaitre dans un état valide et cohérent à tout moment)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Une solution très simple à cette problématique est l’utilisation d’un Mutex ou Monitor (le monitor étant une version allégée du Mutex, nécessitant moins de switch user-mode / kernel-mode):&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;Exemple
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MySharedState &lt;/span&gt;_sharedState = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MySharedState&lt;/span&gt;();

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;FirstThread()
    {
        &lt;span style="color: green"&gt;// make some long-running task

        // get the exclusive access on _sharedState
        &lt;/span&gt;&lt;span style="color: blue"&gt;lock &lt;/span&gt;(_sharedState)
        {
            &lt;span style="color: green"&gt;// read-write access with mutual exclusion
        &lt;/span&gt;}
    }

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;SecondThread()
    {
        &lt;span style="color: green"&gt;// make some long-running task

        // get the exclusive access on _sharedState
        &lt;/span&gt;&lt;span style="color: blue"&gt;lock &lt;/span&gt;(_sharedState)
        {
            &lt;span style="color: green"&gt;// read-write access with mutual exclusion
        &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;Cette solution bien que fonctionnelle, cette solution pose d’importants problèmes :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Si un développeur “oublie” de poser un lock lors d’une lecture-écriture, on peut se retrouver avec un bug de type Race Condition &lt;/li&gt;

  &lt;li&gt;Si un développeur ne pose pas de lock sur un bloc contenant plusieurs lectures de propriétés différentes, il y a un risque d’incohérence (un autre thread aura pu modifier l’état de l’objet entre 2 reads) &lt;/li&gt;

  &lt;li&gt;Un seul thread ne peut entrer dans le lock à un moment T, même si tous les threads concurrents n’ont besoin que d’un accès en lecture (ce qui peut poser un gros problème de performance si la majeur partie des accès se font en lecture seule).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Un objet privatisable pallie à tous ces problèmes. L’idée est que l’état partagé est accessible en lecture seule par défaut, et pour pouvoir le modifier, il faut d’abord le “privatiser” (si on essaie de modifier une propriété sans privatiser l’objet auparavant, on reçoit une exception). Privatiser un objet revient à poser un verrou exclusif en lecture-écriture sur l’objet pour le thread courant. Un seul thread peut privatiser l’objet à chaque instant, et pendant toute la durée de la privatisation, les accès à l’objet (en écriture comme en lecture) sont bloqués (grâce à un ReaderWriterLockSlim). Une fois les modifications terminées, le thread “owner” publie l’objet qui redevient accessible en lecture seule pour tout le monde jusqu’à la prochaine privatisation. De plus, plusieurs threads peuvent accéder simultanément en lecture-seule à l’objet, pour éviter des problèmes de performance.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Les lectures concurrentes ne s’entre-bloquent pas, les “états intermédiaires” ne sont visibles que par le thread responsable du changement d’état, et les développeurs n’ont pas besoin de poser un “lock” manuellement.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Bien sûr, la création d’un tel objet n’est pas forcément super simple, surtout si en plus de ca, l’objet est une source de data-binding dans un client riche (il faut alors retarder les évènements PropertyChanged / CollectionChanged afin que le thread GUI ne soit pas bloqué trop longtemps sur une ré-évaluation de propriété). J’ai donc créé 3 classes réutilisables simplement pour créer des objets privatizables :&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PrivatizableObject : classe abstraite fournissant le comportement de base, implémentant INotifyPropertyChanged avec retardement, et permettant la privatisation de graphes d’objets complexes &lt;/li&gt;

  &lt;li&gt;PrivatizableList&amp;lt;T&amp;gt; : dérive de PrivatizableObject et implémentant IList&amp;lt;T&amp;gt; &lt;/li&gt;

  &lt;li&gt;PrivatizableObservableCollection&amp;lt;T&amp;gt; : dérive de PrivatizableList&amp;lt;T&amp;gt; et implémente INotifyCollectionChanged avec retardement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour créer un PrivatizableObject personnalisé, il suffit alors de dériver de PrivatizableObject, et d’utiliser la syntaxe suivante pour déclarer une propriété :&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestablePrivatizableObject &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;PrivatizableObject
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_testProperty;
    &lt;span style="color: blue"&gt;public string &lt;/span&gt;TestProperty
    {
        &lt;span style="color: blue"&gt;get
        &lt;/span&gt;{
            &lt;span style="color: blue"&gt;base&lt;/span&gt;.BeginRead();
            &lt;span style="color: blue"&gt;string &lt;/span&gt;value = _testProperty;
            &lt;span style="color: blue"&gt;base&lt;/span&gt;.EndRead();
            &lt;span style="color: blue"&gt;return &lt;/span&gt;value;
        }
        &lt;span style="color: blue"&gt;set
        &lt;/span&gt;{
            MarkPropertyChanged(&lt;span style="color: #a31515"&gt;"TestProperty"&lt;/span&gt;);
            _testProperty = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;TestablePrivatizableObject(&lt;span style="color: blue"&gt;bool &lt;/span&gt;privatize) 
        : &lt;span style="color: blue"&gt;base&lt;/span&gt;(privatize)
    { }

    &lt;span style="color: blue"&gt;public &lt;/span&gt;TestablePrivatizableObject(&lt;span style="color: #2b91af"&gt;PrivatizableObject &lt;/span&gt;privatizationController)
        : &lt;span style="color: blue"&gt;base&lt;/span&gt;(privatizationController) { }
}&lt;/pre&gt;

&lt;pre class="code"&gt; &lt;/pre&gt;

&lt;p&gt;Comme vous pouvez le voir, l’implémentation n’a plus grand chose de compliqué !&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;A l’utilisation, là aussi rien de bien méchant :&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Accéder à une propriété :&lt;/p&gt;

&lt;p&gt;string value = myObject.TestProperty;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Modifier l’état partagé:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;(myObject.Privatize())
{
    myObject.TestProperty = &lt;span style="color: #a31515"&gt;"test"&lt;/span&gt;;&lt;br /&gt;    myObject.TestProperty2 = &lt;span style="color: #a31515"&gt;"test2"&lt;/span&gt;; 
} // a la fin du bloc, l’objet est automatiquement publié&lt;/pre&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Effectuer une série de “reads” atomique : &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;using &lt;/span&gt;(testee.CreateReadRegion())
{&lt;br /&gt;    value1 = myObject.TestProperty;&lt;br /&gt;    value2 = myObject.TestProperty2;
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Cette solution, bien que fournie avec une batterie de tests unitaires, est fournie “as-is”, mais est totalement libre de droits :&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.simonferquel.net/blog/SStuff.Parallel.zip"&gt;Téléchargez la solution&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/53.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=GSZCGmnhQtw:mC5lqMBiLN4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=GSZCGmnhQtw:mC5lqMBiLN4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=GSZCGmnhQtw:mC5lqMBiLN4: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=GSZCGmnhQtw:mC5lqMBiLN4: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=GSZCGmnhQtw:mC5lqMBiLN4: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=GSZCGmnhQtw:mC5lqMBiLN4: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/GSZCGmnhQtw" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/09/04/concurrency-privatizable-shared-state.aspx</guid>
            <pubDate>Fri, 04 Sep 2009 08:19:20 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/53.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/09/04/concurrency-privatizable-shared-state.aspx#feedback</comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/53.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/53.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/09/04/concurrency-privatizable-shared-state.aspx</feedburner:origLink></item>
        <item>
            <title>[Perso] Bybye Winwise</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/FZScATO3kSk/perso-bybye-winwise.aspx</link>
            <description>&lt;p&gt;Avant-hier vient de s’achever une page de ma vie professionnelle importante : mon job (chez Winwise) vient de se terminer. J’ai donc désormais pas mal de temps libre, et quelques articles techniques ne devraient pas tarder à voir le jour sur ce blog (notamment des choses autour du développement parallèle, et sûrement une série sur DirectX 10, maintenant que j’ai montré comment faire interagir WPF avec cette technologie).&lt;/p&gt;  &lt;p&gt;Je profite aussi de ce post pour vous rappeler que mes bons services sont à louer… Donc si vous avec des besoins particuliers en conseil ou développement custom autour des technologies .Net (et plus particulièrement C# 3.0 / Linq, WPF, Silverlight, WCF, Visual Studio SDK, DirectX, C++ / CLI ou développement parallèle), n’hésitez pas à me contacter via ce blog.&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/52.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=FZScATO3kSk:1HB7YLLvTUg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=FZScATO3kSk:1HB7YLLvTUg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=FZScATO3kSk:1HB7YLLvTUg: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=FZScATO3kSk:1HB7YLLvTUg: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=FZScATO3kSk:1HB7YLLvTUg: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=FZScATO3kSk:1HB7YLLvTUg: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/FZScATO3kSk" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/09/02/perso-bybye-winwise.aspx</guid>
            <pubDate>Wed, 02 Sep 2009 09:31:34 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/52.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/09/02/perso-bybye-winwise.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/52.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/52.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/09/02/perso-bybye-winwise.aspx</feedburner:origLink></item>
        <item>
            <title>[WPF / DirectX] Interop&amp;eacute;rabilit&amp;eacute; WPF / DirectX 10</title>
            <link>http://feedproxy.google.com/~r/Simonferquelnet/~3/5wBRR5iqugQ/wpf--directx-interopeacuterabiliteacute-wpf--directx-10.aspx</link>
            <description>&lt;p&gt;Depuis la version 3.5 SP1 du Framework .Net, il est possible en WPF de consommer une surface rendue à l’aide de DirectX 9 (grâce à XNA, Managed DirectX ou en C++ / CLI). Malheureusement, de base, WPF ne supporte pas les textures produites par DirectX 10. D’autres solutions existent, comme par exemple l’utilisation de SlimDX, mais jusqu’à maintenant, elles passaient toutes par de l’interopérabilité Win32, et ne permettaient donc pas d’intégrer le contenu DX10 au moteur d’animations / transformations de WPF. &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;Le but de cet article est de montrer une technique permettant sous Windows VISTA, 7 et à priori supérieur d’injecter une surface rendue en DirectX 10 dans le moteur de composition de WPF. &lt;/p&gt;&lt;p align="center"&gt;&lt;a href="http://simonferquel.net/blog/images/simonferquel_net/blog/WindowsLiveWriter/WPFDirectXInteroprabilitWPFDirectX10_10A06/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Un nain rendu en DirectX10 intégré à WPF" border="0" alt="Un nain rendu en DirectX10 intégré à WPF" src="http://simonferquel.net/blog/images/simonferquel_net/blog/WindowsLiveWriter/WPFDirectXInteroprabilitWPFDirectX10_10A06/image_thumb.png" width="626" height="484" /&gt;&lt;/a&gt; &lt;br /&gt;Un nain rendu en DirectX10 / HLSL4 et mélangé à du contenu WPF&lt;/p&gt; &lt;p align="center"&gt; &lt;/p&gt; &lt;h2&gt;Le principe&lt;/h2&gt; &lt;p&gt;Le principe est d’exploiter les fonctionnalités apportées par Windows VISTA et son système WDDM (Windows Display Driver Model) à DirectX 9 et plus particulièrement le système de partage de ressources, qui permet de partager des objets en mémoire sur le GPU entre plusieurs devices DirectX. On va donc créer à partir d’un Device DirectX 9 Ex (DirectX 9 Ex est la version de DirectX9 adaptée au WDDM de VISTA / 7) une texture que l’on va partager avec un Device DirectX10, effectuer un rendu dedans à l’aide de DirectX 10, et la présenter à WPF grâce à DirectX 9. Les performances sont assurées grâce au fait que le partage de ressources tel qu’implémenté dans Windows VISTA / 7 n’implique pas de recopie en mémoire système : la texture ne quitte jamais la mémoire de la carte graphique, de son rendu en DirectX10 jusqu’à son exploitation par le moteur de composition de WPF (basé lui-même sur DirectX 9 Ex). &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;h2&gt;Les obstacles&lt;/h2&gt; &lt;p&gt;L’obstacle le plus gênant a été de trouver de la documentation sur le Resource Sharing entre DirectX 9 et DirectX 10. Il y’a effectivement pas mal de contraintes, et les formats de textures supportés à la fois par DirectX9 et DirectX 10 ne sont pas légions… Et aucun d’entre eux n’est compatible avec WPF ! &lt;/p&gt;&lt;p&gt; &lt;/p&gt; &lt;p&gt;Il a donc fallu passer par une technique de conversion bien connue des développeurs Direct3D (et dont les performances sont impressionnantes par rapport à ce qu’on obtiendrait en faisant ca sur le CPU) baptisée empiriquement la technique des 2 gros triangles. Il s’agit simplement de créer une texture DirectX 9 compatible WPF, et d’effectuer dedans le rendu de 2 polygones recouvrant l’intégralité du ViewPort, auxquels on applique la texture non supportée (pour des performances optimales, on désactive le plus de traitements possibles, notamment la rastérisation, l’éclairage, le Z-Buffer…). &lt;/p&gt;&lt;p&gt; &lt;/p&gt; &lt;h2&gt;La réalisation&lt;/h2&gt; &lt;p&gt;La réalisation ensuite est relativement simple (pour peu que l’on connaisse un minimum WPF, C++ / CLI et les API DirectX). &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;On se retrouve effectivement avec une classe C++ Native dont le but est de créer les Devices DirectX 9 EX et DirectX 10, leurs ressources associées et d’effectuer le rendu, une classe C++ / CLI servant de proxy à la classe de rendu, et un contrôle WPF récupérant le handle de surface DirectX 9 Ex et l’affichant grâce au composant D3DImage (faites une recherche sur votre moteur de recherche préféré sur D3DImage, y’a pas mal de documentation sur le sujet). Dans l’exemple illustrant cet article, le composant WPF envoie les paramètres de rendu à la classe proxy qui appelle la classe de rendu qui charge alors les fichiers de modèles, les shaders et quelques paramètres associés. &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;Voici quelques morceaux de choix du code de l’exemple : &lt;/p&gt;&lt;p&gt;  &lt;/p&gt;&lt;p&gt;Création des textures DirectX 9 (NativeRenderer.cpp) : &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Creating DX9 textures 

&lt;/span&gt;HRESULT hr = m_deviceEx-&amp;gt;CreateTexture(width,
    height,
    1,
    D3DUSAGE_RENDERTARGET,
    D3DFMT_A16B16G16R16F, &lt;span style="color: green"&gt;// Required for DirectX10 Interop
    // but does not work with WPF D3DImage. So we need to copy into an other 
    // D3D9 texture with correct WPF format. For this we simply render a rectangle
    &lt;/span&gt;D3DPOOL_DEFAULT, 
    &amp;amp;m_renderTexture,
    &amp;amp;shareHandle);
assert(SUCCEEDED(hr));

&lt;span style="color: green"&gt;// This texture will be passed to WPF D3DImage
&lt;/span&gt;hr = m_deviceEx-&amp;gt;CreateTexture(width,
    height,
    1,
    D3DUSAGE_RENDERTARGET,
    D3DFMT_A8R8G8B8,
    D3DPOOL_DEFAULT,
    &amp;amp;m_renderTextureCopy,
    NULL);
assert(SUCCEEDED(hr));&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Ouverture de la texture partagée par le device DirectX 10
&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Now we open the shared texture from the DX10 Device
&lt;/span&gt;ID3D10Resource * pTempResource;
hr = m_device10-&amp;gt;OpenSharedResource(shareHandle, &lt;span style="color: blue"&gt;__uuidof&lt;/span&gt;(ID3D10Resource), (&lt;span style="color: blue"&gt;void&lt;/span&gt;**)&amp;amp;pTempResource);
assert(SUCCEEDED(hr));
hr = pTempResource-&amp;gt;QueryInterface(&lt;span style="color: blue"&gt;__uuidof&lt;/span&gt;(ID3D10Texture2D), (&lt;span style="color: blue"&gt;void&lt;/span&gt;**)&amp;amp;m_renderTexture10);
assert(SUCCEEDED(hr));
SAFE_RELEASE(pTempResource);

&lt;span style="color: green"&gt;// And we create a Render Target View from it
&lt;/span&gt;hr = m_device10-&amp;gt;CreateRenderTargetView(m_renderTexture10, NULL, &amp;amp;m_rtv);
assert(SUCCEEDED(hr));&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Configuration du pipeline DX9 pour la conversion de texture à l’aide des 2 gros triangles
&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// The texture in which DX10 content is drawn is set as an input Texture
// in the DX9 device
&lt;/span&gt;hr = m_deviceEx-&amp;gt;SetTexture(0, m_renderTexture);
assert(SUCCEEDED(hr));


&lt;span style="color: green"&gt;// And the output is set to the texture which has a WPF compatible format
&lt;/span&gt;hr = m_renderTextureCopy-&amp;gt;GetSurfaceLevel(0, &amp;amp;m_renderTarget);
assert(SUCCEEDED(hr));

hr = m_deviceEx-&amp;gt;SetRenderTarget(0, m_renderTarget);
assert(SUCCEEDED(hr));&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// This is the rectangle that will be used for the texture conversion 
// rendering pass
&lt;/span&gt;m_quad[0].x = 0;
m_quad[0].y = 0;
m_quad[0].z = 0.5;
m_quad[0].rhw = 1.0;
m_quad[0].u = 0;
m_quad[0].v = 0;

m_quad[1].x = (&lt;span style="color: blue"&gt;float&lt;/span&gt;)width;
m_quad[1].y = 0;
m_quad[1].z = 0.5;
m_quad[1].rhw = 1.0;
m_quad[1].u = 1;
m_quad[1].v = 0;

m_quad[2].x = 0;
m_quad[2].y = (&lt;span style="color: blue"&gt;float&lt;/span&gt;)height;
m_quad[2].z = 0.5;
m_quad[2].rhw = 1.0;
m_quad[2].u = 0;
m_quad[2].v = 1;

m_quad[3].x = (&lt;span style="color: blue"&gt;float&lt;/span&gt;)width;
m_quad[3].y = (&lt;span style="color: blue"&gt;float&lt;/span&gt;)height;
m_quad[3].z = 0.5;
m_quad[3].rhw = 1.0;
m_quad[3].u = 1;
m_quad[3].v = 1;

IDirect3DVertexBuffer9* vertBuffer;
hr = m_deviceEx-&amp;gt;CreateVertexBuffer(4*&lt;span style="color: blue"&gt;sizeof&lt;/span&gt;(QuadVertex), &lt;br /&gt;         D3DUSAGE_WRITEONLY, &lt;br /&gt;         QUAD_FORMAT, &lt;br /&gt;         D3DPOOL_DEFAULT, &amp;amp;vertBuffer,NULL);
assert(SUCCEEDED(hr));
&lt;span style="color: blue"&gt;void&lt;/span&gt;* bufferData = NULL;
hr = vertBuffer-&amp;gt;Lock(0,0, &amp;amp;bufferData, 0);
memcpy(bufferData, (&lt;span style="color: blue"&gt;void&lt;/span&gt;*)m_quad, 4*&lt;span style="color: blue"&gt;sizeof&lt;/span&gt;(QuadVertex));
vertBuffer-&amp;gt;Unlock();

hr = m_deviceEx-&amp;gt;SetStreamSource(0, vertBuffer, 0, &lt;span style="color: blue"&gt;sizeof&lt;/span&gt;(QuadVertex));
assert(SUCCEEDED(hr));
SAFE_RELEASE(vertBuffer);&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;Rendu (effectué sur l’évènement Rendering du CompositionTarget) :
&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;pre class="code"&gt;HRESULT hr;

&lt;span style="color: blue"&gt;if&lt;/span&gt;(m_rtv == NULL)
    &lt;span style="color: blue"&gt;return&lt;/span&gt;;

&lt;span style="color: green"&gt;// Send the transformation matrices to the GPU
&lt;/span&gt;ApplyMatrices();

&lt;span style="color: green"&gt;// Update the BumpForce shader variable
&lt;/span&gt;m_fBumpForceVariable-&amp;gt;SetFloat(m_bumpForce);

&lt;span style="color: green"&gt;// Update the fTime shader variable
&lt;/span&gt;&lt;span style="color: blue"&gt;float &lt;/span&gt;time = (&lt;span style="color: blue"&gt;float&lt;/span&gt;)m_stopWatch.GetElapsedSeconds();
m_fTimeVariable-&amp;gt;SetFloat(time);

&lt;span style="color: green"&gt;// Clear the Depth Buffer
&lt;/span&gt;m_device10-&amp;gt;ClearDepthStencilView(m_dsv, D3D10_CLEAR_DEPTH, 1.0,0);

&lt;span style="color: green"&gt;// Clear the render target
&lt;/span&gt;&lt;span style="color: blue"&gt;float &lt;/span&gt;clearColor[] = {0.0,0.0,0.0,.0};
m_device10-&amp;gt;ClearRenderTargetView(m_rtv, clearColor);    

&lt;span style="color: green"&gt;// Render the mesh
&lt;/span&gt;&lt;span style="color: blue"&gt;if&lt;/span&gt;(m_meshManager != NULL)
{
    ID3DX10Mesh *mesh = m_meshManager-&amp;gt;GetMesh();
    
    ID3D10InputLayout * inputLayout = m_meshManager-&amp;gt;GetInputLayout();
    m_device10-&amp;gt;IASetInputLayout(inputLayout);

    DWORD partCount = m_meshManager-&amp;gt;GetMaterialCount();
    D3D10_TECHNIQUE_DESC td;

    &lt;span style="color: blue"&gt;for&lt;/span&gt;(DWORD i = 0;i&amp;lt;partCount;i++)
    {
        &lt;span style="color: blue"&gt;const &lt;/span&gt;MATERIAL10* mat = m_meshManager-&amp;gt;GetMaterial(i);
        m_txDiffuseVariable-&amp;gt;SetResource(mat-&amp;gt;diffuseMap);
        m_txBumpVariable-&amp;gt;SetResource(mat-&amp;gt;bumpMap);
        m_renderTechnique-&amp;gt;GetDesc(&amp;amp;td);
        m_hasEffect9Variable-&amp;gt;SetBool((BOOL)mat-&amp;gt;hasEffect9 &amp;amp;&amp;amp; m_activateSpecularLighting);
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(DWORD p = 0; p &amp;lt; td.Passes;p++)
        {
            ID3D10EffectPass *pass = m_renderTechnique-&amp;gt;GetPassByIndex(p);
            pass-&amp;gt;Apply(0);
            HRESULT hr;
            hr = mesh-&amp;gt;DrawSubset(i);
            
            assert(SUCCEEDED(hr));
        }
    }
}

&lt;span style="color: green"&gt;// Flush the generated content
&lt;/span&gt;m_device10-&amp;gt;Flush();



&lt;span style="color: green"&gt;// Begin the DX9 pass
&lt;/span&gt;m_deviceEx-&amp;gt;BeginScene();

&lt;span style="color: green"&gt;// Clear the WPF Render Target
&lt;/span&gt;hr = m_deviceEx-&amp;gt;Clear(0,NULL,D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 1.0,0);

&lt;span style="color: green"&gt;// Draw the 2 big triangles
&lt;/span&gt;hr = m_deviceEx-&amp;gt;DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

&lt;span style="color: green"&gt;// End the DX9 pass
&lt;/span&gt;m_deviceEx-&amp;gt;EndScene();
hr = m_deviceEx-&amp;gt;Present(NULL,NULL,NULL,NULL);&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Si ce code ne vous fait pas peur, à priori je n’ai pas besoin de vous mettre en évidence le code de la classe proxy ni celle du contrôle WPF. Vous pouvez retrouver l’intégralité du code (et des assets graphiques tirés des samples du SDK DirectX) &lt;a href="http://www.simonferquel.net/blog/WPFDirect3DSample.zip"&gt;ici.&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;Les pré-requis sont :
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;VS 2008 SP1 (avec support de C# et C++)&lt;/li&gt;
&lt;li&gt;Windows Vista ou 7&lt;/li&gt;
&lt;li&gt;Une carte 3D DirectX 10&lt;/li&gt;
&lt;li&gt;Le SDK DirectX de mars 2009&lt;/li&gt;
&lt;li&gt;Les C++ Directories bien configurés dans Visual Studio pour pouvoir accéder aux includes / libs du sdk DirectX&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Cette technique ouvre la porte à de nouveaux scénarios d’intéraction avec du contenu DirectX. On peut imaginer des outils de production 3D, des gestionnaires d’assets pour des éditeurs de jeu vidéo, des environements de développement de hlsl, des interfaces de simulation en 3D… Le tout en obtenant à la fois les avantages de la productivité apportée par WPF, et les performances et les possibilités en terme de rendu 3D de DirectX 10 (et apriori, la même chose sera possible avec DirectX 11 !)&lt;/p&gt;&lt;img src="http://www.simonferquel.net//blog/aggbug/51.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=5wBRR5iqugQ:FHrysUPPm-Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Simonferquelnet?i=5wBRR5iqugQ:FHrysUPPm-Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Simonferquelnet?a=5wBRR5iqugQ:FHrysUPPm-Y: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=5wBRR5iqugQ:FHrysUPPm-Y: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=5wBRR5iqugQ:FHrysUPPm-Y: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=5wBRR5iqugQ:FHrysUPPm-Y: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/5wBRR5iqugQ" height="1" width="1"/&gt;</description>
            <dc:creator>Simon FERQUEL</dc:creator>
            <guid isPermaLink="false">http://www.simonferquel.net//blog/archive/2009/07/24/wpf--directx-interopeacuterabiliteacute-wpf--directx-10.aspx</guid>
            <pubDate>Fri, 24 Jul 2009 16:54:57 GMT</pubDate>
            <wfw:comment>http://www.simonferquel.net//blog/comments/51.aspx</wfw:comment>
            <comments>http://www.simonferquel.net//blog/archive/2009/07/24/wpf--directx-interopeacuterabiliteacute-wpf--directx-10.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://www.simonferquel.net//blog/comments/commentRss/51.aspx</wfw:commentRss>
            <trackback:ping>http://www.simonferquel.net//blog/services/trackbacks/51.aspx</trackback:ping>
        <feedburner:origLink>http://www.simonferquel.net//blog/archive/2009/07/24/wpf--directx-interopeacuterabiliteacute-wpf--directx-10.aspx</feedburner:origLink></item>
        <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>
            <slash:comments>1</slash: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>7</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>
    </channel>
</rss>
