<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog Experida -  Alexandre Arnaudet</title>
	<atom:link href="http://blog.experida.fr/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.experida.fr</link>
	<description></description>
	<lastBuildDate>Mon, 19 Dec 2011 22:41:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Silverlight&#8211;Indiquer &#224; l&#8217;utilisateur si des modifications sont en cours avant de changer de page</title>
		<link>http://blog.experida.fr/2011/12/20/silverlightindiquer-lutilisateur-si-des-modifications-sont-en-cours-avant-de-changer-de-page/</link>
		<comments>http://blog.experida.fr/2011/12/20/silverlightindiquer-lutilisateur-si-des-modifications-sont-en-cours-avant-de-changer-de-page/#comments</comments>
		<pubDate>Mon, 19 Dec 2011 22:28:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Notification changement]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/12/20/silverlightindiquer-lutilisateur-si-des-modifications-sont-en-cours-avant-de-changer-de-page/</guid>
		<description><![CDATA[Depuis la version 2 de Silverlight, il est comme vous le savez, possible de mettre en place une navigation par page. Afin que celle-ci fonctionne correctement il faut donc un UserControl contenant une NavigationFrame avec un UriMapper configuré comme par exemple dans le XAML suivant: &#60;navigation:Frame x:Name=&#34;MasterPageContentFrame&#34; Style=&#34;{StaticResource ContentFrameStyle}&#34;&#62; &#60;navigation:Frame.UriMapper&#62; &#60;uriMapper:UriMapper&#62; &#60;uriMapper:UriMapping Uri=&#34;/{SubDirectory}/{pageName}&#34; MappedUri=&#34;/Views/{SubDirectory}/{pageName}.xaml&#34;/&#62; &#60;/uriMapper:UriMapper&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Depuis la version 2 de Silverlight, il est comme vous le savez, possible de mettre en place une navigation par page. Afin que celle-ci fonctionne correctement il faut donc un UserControl contenant une NavigationFrame avec un UriMapper configuré comme par exemple dans le XAML suivant:</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame
     </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;MasterPageContentFrame&quot;
     </span><span style="color: red">Style</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">StaticResource </span><span style="color: red">ContentFrameStyle</span><span style="color: blue">}&quot;</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame.UriMapper</span><span style="color: blue">&gt;
       &lt;</span><span style="color: #a31515">uriMapper</span><span style="color: blue">:</span><span style="color: #a31515">UriMapper</span><span style="color: blue">&gt;
         &lt;</span><span style="color: #a31515">uriMapper</span><span style="color: blue">:</span><span style="color: #a31515">UriMapping </span><span style="color: red">Uri</span><span style="color: blue">=&quot;/{SubDirectory}/{pageName}&quot; </span><span style="color: red">MappedUri</span><span style="color: blue">=&quot;/Views/{SubDirectory}/{pageName}.xaml&quot;/&gt;
       &lt;/</span><span style="color: #a31515">uriMapper</span><span style="color: blue">:</span><span style="color: #a31515">UriMapper</span><span style="color: blue">&gt;
      &lt;/</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame.UriMapper</span><span style="color: blue">&gt;
 &lt;/</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame</span><span style="color: blue">&gt;</span></pre>
<p>Dans cet article je vous propose de mettre en place un système permettant de notifier l’utilisateur si il essaie de naviguer vers une autre page, alors que des modifications sont en cours.</p>
<p><span id="more-315"></span>
<p align="justify">Par modifications en cours il pourrait s’agir d’un changement non validé du model, ou d’un état non valide du ViewModel pour les personnes souhaitant mettre en place MVVM.</p>
<p align="justify">Notre service chargé de cette opération est composé de deux parties.</p>
<ul>
<li>
<div align="justify">La première, pièce essentielle du service sera représentée par une interface nommée ITracker</div>
</li>
<li>
<div align="justify">La seconde, utilisée par ITracker sera nommée ITrackedPart.</div>
</li>
</ul>
<p align="justify">Comme vous l’aurez compris en voyant les noms donnés, ITracker sera chargé d’effectuer le suivi des ITrackedPart et par conséquent indiquer si au moins une ITrackedPart contient une modification.</p>
<p>Regardons plus en détail ces éléments en commençant par l’interface ITracker.</p>
<div align="left">
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">ITracker
    </span>{
        <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">ITrackedPart</span>&gt; TrakerStore { <span style="color: blue">get</span>; }
        <span style="color: blue">void </span>Register(<span style="color: #2b91af">ITrackedPart</span>[] trackers);
        <span style="color: blue">void </span>UnRegister(<span style="color: #2b91af">ITrackedPart</span>[] trackers);
        <span style="color: blue">bool </span>HasChanges { <span style="color: blue">get</span>; }
    }</pre>
</div>
<div align="justify">Comme indiqué juste avant, ITracker possède une propriété “TrackerStore” permettant de stocker les ITrackedPart, ainsi qu’une propriété “HasChanges” pour connaitre l’état actuel des éléments que l’on surveille.</div>
<div align="justify">Notez également la présence des méthodes “Register” et “Unregister&quot; pour inscrire / désinscrire des parts du store.</div>
<div align="justify">&#160;</div>
<div align="justify">Du côté d’ItrackedPart l’interface est également relativement simple avec ces deux propriétés et son unique méthode:</div>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">ITrackedPart
    </span>{<span style="color: gray">
        </span><span style="color: blue">bool </span>PartHasChanges { <span style="color: blue">get</span>; }
     <span style="color: gray">   </span><span style="color: blue">bool </span>IsChangeTrackingEnabled { <span style="color: blue">get</span>; }
<span style="color: gray">        </span><span style="color: blue">void </span>MarkChangesAsHandled();
    }</pre>
<ul>
<li>
<div align="justify">PartHasChanges indique si il y a des changements.</div>
</li>
<li>
<div align="justify">IsChangeTrackingEnabled permet de faire savoir au ITracker si la surveillance est active sur cette part.</div>
</li>
<li>
<div align="justify">Enfin la méthode MarkChangesAsHandled, permet de faire savoir à la part que les changements sont considérés comme ayant été validés.</div>
</li>
</ul>
<p>Regardons maintenant comment implémenter ces deux interfaces:</p>
<p>Pour le Tracker voici une implémentation fonctionnant dans un environnement avec MEF:</p>
<pre class="code">    [<span style="color: #2b91af">Export</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">ITracker</span>))]
    [<span style="color: #2b91af">PartCreationPolicy</span>(<span style="color: #2b91af">CreationPolicy</span>.Shared)]
    <span style="color: blue">public class </span><span style="color: #2b91af">Tracker </span>: <span style="color: #2b91af">ITracker</span>, <span style="color: #2b91af">IDisposable
    </span>{
        <span style="color: blue">private </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">ITrackedPart</span>&gt; trackerStore = <span style="color: blue">null</span>;

        <span style="color: blue">public </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">ITrackedPart</span>&gt; TrakerStore { <span style="color: blue">get </span>{ <span style="color: blue">return </span>trackerStore; } }

        [<span style="color: #2b91af">ImportingConstructor</span>]
        <span style="color: blue">public </span>Tracker()
        {
            trackerStore = <span style="color: blue">new </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">ITrackedPart</span>&gt;();
        }

        <span style="color: blue">#region </span>IPropertyChangeNotifier Members

        <span style="color: blue">public void </span>Register(<span style="color: #2b91af">ITrackedPart</span>[] trackers)
        {
            <span style="color: blue">if </span>(trackers == <span style="color: blue">null</span>)
                <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;trackers&quot;</span>);

                <span style="color: blue">foreach </span>(<span style="color: #2b91af">ITrackedPart </span>p <span style="color: blue">in </span>trackers)
                {
                    <span style="color: blue">if </span>(!trackerStore.Contains(p))
                        trackerStore.Add(p);
                }

        }

        <span style="color: blue">public bool </span>HasChanges
        {
            <span style="color: blue">get
            </span>{
                <span style="color: blue">return </span>trackerStore.Any(t =&gt; t.IsChangeTrackingEnabled &amp;&amp; t.PartHasChanges);
            }
        }

        <span style="color: blue">public void </span>UnRegister(<span style="color: #2b91af">ITrackedPart</span>[] trackers)
        {
            <span style="color: blue">if </span>(trackers == <span style="color: blue">null</span>)
                <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;trackers&quot;</span>);

                <span style="color: blue">foreach </span>(<span style="color: #2b91af">ITrackedPart </span>p <span style="color: blue">in </span>trackers)
                {
                    <span style="color: blue">if </span>(trackerStore.Contains(p))
                        trackerStore.Remove(p);
                }
        }

        <span style="color: blue">#endregion

        #region </span>IDisposable Members

        <span style="color: blue">public void </span>Dispose()
        {
                trackerStore.Clear();
                trackerStore = <span style="color: blue">null</span>;
        }

        <span style="color: blue">#endregion
    </span>}</pre>
<p>Mise à part les deux attributs spécifiques à MEF, indiquant que l’on fournit un export de type ITracker&#160; et que ce dernier est de type singleton, le code est simple à comprendre.</p>
<p>Pour ITrackedPart la solution est un peu plus complexe, puisque vous pourriez décider de l’implémenter sur des composants différents.</p>
<p>Dans une application Silverlight utilisant les RIAServices on peut tout à fait imaginer que vous souhaitiez savoir si des modifications sont en cours sur un DomainContext. Alors certes vous pourriez dire qu’un DomainContext possède déjà un système permettant de savoir il y a des changements, mais en liant le DomainContext ou d’autres objets à ce service, vous pourrez savoir via un seul service si une modification est en cours.</p>
<p>Exemple d’implémentation sur un DomainContext:</p>
<pre class="code">[<span style="color: #2b91af">Export</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">MyDomainContext</span>))]
[<span style="color: #2b91af">PartCreationPolicy</span>(<span style="color: #2b91af">CreationPolicy</span>.NonShared)]
    <span style="color: blue">public partial class </span><span style="color: #2b91af">MyDomainContext </span>: <span style="color: #2b91af">ITrackedPart
    </span>{
        <span style="color: blue">#region </span>IChangesTracker Members

        <span style="color: blue">public bool </span>PartHasChanges
        {
            <span style="color: blue">get </span>{ <span style="color: blue">return this</span>.HasChanges; }
        }

        <span style="color: blue">public bool </span>IsChangeTrackingEnabled
        {
            <span style="color: blue">get </span>{ <span style="color: blue">return true</span>; }
        }

        <span style="color: blue">public void </span>MarkChangesAsHandled()
        {
            <span style="color: blue">if </span>(<span style="color: blue">this</span>.HasChanges)
                <span style="color: blue">this</span>.RejectChanges();
        }
        <span style="color: blue">#endregion

    </span>}</pre>
<p>Pour une implémentation sur un ViewModel, j’ai décidé de créer un attribut servant à décorer les propriétés du ViewModel que l’on souhaite suivre. </p>
<pre class="code">[<span style="color: #2b91af">AttributeUsage</span>(<span style="color: #2b91af">AttributeTargets</span>.Property, AllowMultiple = <span style="color: blue">false</span>, Inherited = <span style="color: blue">false</span>)]
    <span style="color: blue">public class </span><span style="color: #2b91af">TrackedPropertyAttribute </span>: <span style="color: #2b91af">Attribute
    </span>{
    }</pre>
<p>Pour l’utiliser ajoutez le de cette manière:</p>
<pre class="code">[<span style="color: #2b91af">TrackedProperty</span>]
<span style="color: blue">public </span>MyType MyProperty</pre>
<p>Il ne vous reste plus qu’à implémenter l’interface ITrackedPart sur votre ViewModel comme dans l’exemple suivant et à enregistrer le ViewModel via la propriété Register du Tracker.</p>
<pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">ViewModelBase</span>:<span style="color: #2b91af">NotifyPropertyChangedBase</span>,<span style="color: #2b91af">ITrackedPart
</span>{
  [<span style="color: #2b91af">Import</span>(<span style="color: blue">typeof</span>(ITracker), RequiredCreationPolicy = <span style="color: #2b91af">CreationPolicy</span>.Shared)]
  <span style="color: blue">public </span>ITracker Tracker { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

  <span style="color: blue">public </span>ViewModelBase()
  {
         RegisterTracker(<span style="color: blue">new </span><span style="color: #2b91af">ITrackedPart</span>[] { <span style="color: blue">this </span>});
  }

  <span style="color: blue">#region </span>TrackChanges

  <span style="color: gray"> </span><span style="color: blue">protected virtual void </span>RegisterTracker(<span style="color: #2b91af">ITrackedPart</span>[] trackers)
   {
      <span style="color: blue">if </span>(IsChangeTrackingEnabled)
      {
       <span style="color: blue">if </span>(trackers.Contains(<span style="color: blue">this</span>))
            PropertyChanged += <span style="color: blue">new </span>System.ComponentModel.<span style="color: #2b91af">PropertyChangedEventHandler</span>(Tracker_PropertyChanged);
              Tracker.Register(trackers);
          }
      }

      <span style="color: gray"> </span><span style="color: blue">protected virtual void </span>UnRegisterTracker(<span style="color: #2b91af">ITrackedPart</span>[] trackers)
      {
          <span style="color: blue">if </span>(trackers.Contains(<span style="color: blue">this</span>))
              PropertyChanged -= <span style="color: blue">new </span>System.ComponentModel.<span style="color: #2b91af">PropertyChangedEventHandler</span>(Tracker_PropertyChanged);
          Tracker.UnRegister(trackers);
      }

      <span style="color: blue">void </span>Tracker_PropertyChanged(<span style="color: blue">object </span>sender, System.ComponentModel.<span style="color: #2b91af">PropertyChangedEventArgs </span>e)
      {
          <span style="color: #2b91af">Type </span>type = <span style="color: blue">this</span>.GetType();
          <span style="color: #2b91af">PropertyInfo </span>pInfo = type.GetProperty(e.PropertyName);
          <span style="color: #2b91af">TrackedPropertyAttribute </span>attr = pInfo.GetCustomAttributes(<span style="color: blue">false</span>).OfType&lt;<span style="color: #2b91af">TrackedPropertyAttribute</span>&gt;().FirstOrDefault();
          <span style="color: blue">if </span>(attr != <span style="color: blue">null</span>)
              hasChanges = <span style="color: blue">true</span>;
      }

      <span style="color: blue">#endregion

      #region </span>IChangesTracker Members

      <span style="color: blue">private bool </span>hasChanges;

      <span style="color: blue">public bool </span>PartHasChanges
      {
          <span style="color: blue">get
          </span>{
              <span style="color: blue">return </span>hasChanges;
          }
      }

      <span style="color: blue">public virtual bool </span>IsChangeTrackingEnabled
      {
          <span style="color: blue">get </span>{ <span style="color: blue">return true</span>; }
      }

      <span style="color: blue">public void </span>MarkChangesAsHandled()
      {
          hasChanges = <span style="color: blue">false</span>;
      }

      <span style="color: blue">#endregion

  </span>}</pre>
<p>Que pouvons-nous dire sur ce bout de code.</p>
<p>La classe ViewModel hérite de <span style="color: #2b91af">NotifyPropertyChangedBase </span>qui est une classe implémentant l’interface INotifyPropertyChanged. </p>
<p>Grâce à cette classe et juste avant d’enregistrer le viewModel dans le Tracker, nous allons nous abonner à l’event PropertyChanged. Ainsi, lorsqu’une propriété va être modifiée, nous allons juste vérifier si elle est décorée de l’attribut <span style="color: #2b91af">TrackedPropertyAttribute </span>créé un peu plus haut dans ce billet. Si c’est le cas, on assigne simplement la valeur true à une variable de type bool nommée hasChanges pour dire qu’il y a eu une modification. Cette variable est ensuite utilisée par les membres de l’interface ITrackedPart pour indiquer l’état actuel.</p>
<p>Dernier point qu’il nous reste à voir, l’appel du service Tracker lors du changement de la page.</p>
<p>Pour faire simple dans cette démo, je me suis simplement abonné à l’évènement Navigating de la navigation frame de la page principale.</p>
<pre class="code"><span style="color: blue">public void </span>MasterPageContentFrame_Navigating(<span style="color: blue">object </span>sender, <span style="color: #2b91af">NavigatingCancelEventArgs </span>e)
{
<span style="color: blue">  if </span>(Tracker != <span style="color: blue">null </span>&amp;&amp; Tracker.HasChanges)
  {
      e.Cancel = <span style="color: blue">true</span>;
      <span style="color: #2b91af">NotifyChangesWindow </span>w = <span style="color: blue">new </span><span style="color: #2b91af">NotifyChangesWindow</span>();
      w.Closed += (s, ev) =&gt;
      {
        <span style="color: blue">if </span>(w.DialogResult.HasValue &amp;&amp; w.DialogResult.Value)
        {
          Traker.Store.ForEach(p =&gt; p.MarkChangesAsHandled());
          NavigationService.Navigate(e.Uri.ToString());
        }
      };
      w.Show();
  }
}</pre>
<p>Comme le laisse entendre le nom de l’event Navigating, la Navigation ne s’est pas encore passée, on fait donc appel au ITracker et à sa propriété HasChanges qui va nous retourner une réponse de type bool pour dire si des modifications sont en cours sur au moins un des éléments enregistrés dans le Tracker.</p>
<p>Avant toute chose on annule la navigation en cours. Ensuite on lance la fenêtre demandant à l’utilisateur si il souhaite continuer ou pas. Si il le souhaite on ferme la fenêtre de notification et on relance la navigation. Dans le cas contraire on ferme simplement la fenêtre de notification.</p>
<p>Voilà ce billet touche à sa fin. On pourrait très bien ajouter des fonctionnalités plus évoluées à ce service, mais pour cela je laisse faire votre imagination.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/12/20/silverlightindiquer-lutilisateur-si-des-modifications-sont-en-cours-avant-de-changer-de-page/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>R&#233;cup&#233;rer la description d&#8217;une propri&#233;t&#233;</title>
		<link>http://blog.experida.fr/2011/10/31/rcuprer-la-description-dune-proprit/</link>
		<comments>http://blog.experida.fr/2011/10/31/rcuprer-la-description-dune-proprit/#comments</comments>
		<pubDate>Mon, 31 Oct 2011 09:29:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Expression]]></category>
		<category><![CDATA[Linq]]></category>
		<category><![CDATA[DescriptionAttribute]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/10/31/rcuprer-la-description-dune-proprit/</guid>
		<description><![CDATA[Comme vous le savez, lors du design d’un composant, au même titre que l’on utilise des attributs comme “Browsable”,&#160; il est courant d’utiliser l’attribut description pour fournir une description de la propriété qui sera affichée dans un composant graphique tel qu’un property grid. Dans ce billet je vous propose juste de mettre en place une [...]]]></description>
			<content:encoded><![CDATA[<p>Comme vous le savez, lors du design d’un composant, au même titre que l’on utilise des attributs comme “Browsable”,&#160; il est courant d’utiliser l’attribut description pour fournir une description de la propriété qui sera affichée dans un composant graphique tel qu’un property grid.</p>
<p>Dans ce billet je vous propose juste de mettre en place une méthode helper pour simplifier la récupération de cette description par le code.</p>
<p><span id="more-313"></span>
<p>Pour cela, commençons par créer une classe “static” que l’on nommera DescriptionHelper et dans laquelle nous allons également ajouter une méthode générique GetDescription prenant en paramètre une expression.</p>
<pre class="code"><span style="color: blue">public static class </span><span style="color: #2b91af">DescriptionHelper
   </span>{
       <span style="color: blue">public static string </span>GetDescription&lt;T, U&gt;(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;T, U&gt;&gt; exp)
       {

       }
   }</pre>
<p>&#160;</p>
<p>Comme vous pouvez le constater cette méthode est générique et l’on vient de voir qu’elle prend en paramètre une expression. Pourquoi ? </p>
<p><u>Pour deux raisons:</u></p>
<ul>
<li>Premièrement nous allons pouvoir récupérer la description d’une propriété de n’importe quel objet quelque soit son type.</li>
<li>Deuxième point, nous allons pouvoir indiquer la propriété à interroger via une expression lambda et non directement par une string. On évite ainsi toute erreur au runtime suite à une erreur de nommage.</li>
</ul>
<p>Ajoutons&#160; maintenant dans cette méthode le code permettant de récupérer le nom de la propriété.</p>
<pre class="code"><span style="color: blue">if </span>(exp == <span style="color: blue">null</span>)
   <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;exp&quot;</span>);

   <span style="color: blue">var </span>memberExpression = exp.Body <span style="color: blue">as </span><span style="color: #2b91af">MemberExpression</span>;

   <span style="color: blue">if </span>(memberExpression == <span style="color: blue">null </span>||
       memberExpression.Member.MemberType != <span style="color: #2b91af">MemberTypes</span>.Property)
   {
       <span style="color: blue">throw new </span><span style="color: #2b91af">InvalidOperationException</span>();
   }

   <span style="color: blue">return typeof</span>(T).GetPropertyDescription(memberExpression.Member.Name);</pre>
<p>En travaillant avec les MemberExpression, vous pouvez voir comment il est relativement simple de récupérer le nom de la propriété indiquée via l’expression.</p>
<p>Pour enfin récupérer la description nous appelons la méthode GetPropertyDescription en lui passant le nom de la propriété à partir du type d’objet auquel la propriété appartient.</p>
<p>GetPropertyDescription est une petite méthode d’extension qui se base sur le type Type.</p>
<pre class="code"><span style="color: blue">public static class </span><span style="color: #2b91af">TypeExtension
</span>{
  <span style="color: blue">public static string
    </span>GetPropertyDescription(<span style="color: blue">this </span><span style="color: #2b91af">Type </span>type, <span style="color: blue">string </span>propertyName)
  {
   <span style="color: #2b91af">PropertyDescriptor </span>desc =
         <span style="color: #2b91af">TypeDescriptor</span>.GetProperties(type)[propertyName];
   <span style="color: #2b91af">DescriptionAttribute </span>descriptionAttr =
        desc.Attributes.OfType&lt;<span style="color: #2b91af">DescriptionAttribute</span>&gt;().FirstOrDefault();
   <span style="color: blue">return </span>descriptionAttr != <span style="color: blue">null </span>? descriptionAttr.Description : <span style="color: blue">null</span>;
  }
 }</pre>
<p>Comme nous avons le Type de l’objet et le nom de la propriété, nous pouvons récupérer le PropertyDescriptor via la méthode TypeDescriptor.GetProperties et donc accéder aux attributs appliqués à la propriété. Si il existe un attribut de type DescriptionAttribute,on récupère la valeur de la description sinon on retourne null.</p>
<p>Pour terminer ce billet, ajoutons un exemple.</p>
<p>Partons du principe que nous avons une entité InfoDemandeur avec une propriété Adresse. Pour récupérer la description liée à la propriété Adresse, il suffit d’insérer la ligne de code suivante:</p>
<pre class="code"><span style="color: blue">string </span>description =
     <span style="color: #2b91af">DescriptionHelper</span>.GetDescription&lt;<span style="color: #2b91af">InfoDemandeur</span>, <span style="color: blue">string</span>&gt;(i =&gt; i.Adresse);</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/10/31/rcuprer-la-description-dune-proprit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>D&#233;marrer une animation sur un nouveau thread d&#8217;UI</title>
		<link>http://blog.experida.fr/2011/10/11/dmarrer-une-animation-sur-un-nouveau-thread-dui/</link>
		<comments>http://blog.experida.fr/2011/10/11/dmarrer-une-animation-sur-un-nouveau-thread-dui/#comments</comments>
		<pubDate>Tue, 11 Oct 2011 09:08:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[Dispatcher]]></category>
		<category><![CDATA[Thread]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/10/11/dmarrer-une-animation-sur-un-nouveau-thread-dui/</guid>
		<description><![CDATA[Récemment j’ai utilisé un contrôle d’une librairie tierce permettant de générer des rapports.&#160; Ce contrôle relativement complexe pouvait mettre jusqu’à plusieurs secondes pour s’afficher correctement selon la machine sur laquelle est exécutée l’application. Le chargement du contrôle est lié au thread de l’interface utilisateur et le temps que le contrôle n’est pas entièrement chargé l’utilisateur [...]]]></description>
			<content:encoded><![CDATA[<p>Récemment j’ai utilisé un contrôle d’une librairie tierce permettant de générer des rapports.&#160; Ce contrôle relativement complexe pouvait mettre jusqu’à plusieurs secondes pour s’afficher correctement selon la machine sur laquelle est exécutée l’application. </p>
<p>Le chargement du contrôle est lié au thread de l’interface utilisateur et le temps que le contrôle n’est pas entièrement chargé l’utilisateur ne peut effectuer aucune autre action via l’interface. Une interface non utilisable, même quelques secondes peut être qualifiée comme un “plantage”, et il n’est pas rare de voir alors l’utilisateur essayer de cliquer plusieurs fois.</p>
<p><span id="more-311"></span>
<p>En WPF, lorsque l’application est démarrée, un thread dédié à l’UI est créé. Tout contrôle créé sur ce thread ne peut être utilisé sur un autre thread. C’est ce qu’on appelle l’affinité de thread. </p>
<p>Cette affinité est gérée par la classe Dispatcher. Il faut voir le dispatcher comme un ensemble de messages priorisés. Chaque message est alors exécuté selon la priorité qui lui est associée et impacte l’UI. Une instance de dispatcher est associée à un et un seul thread d’UI.</p>
<p>Si on revient au problème initial, à savoir que l’interface est bloquée pendant quelques secondes, j’aimerais afficher une animations pour indiquer à l’utilisateur qu’une opération est en cours.</p>
<p>D’après ce qu’on a vu, une solution est donc de créer un nouveau thread, auquel nous allons associé un nouveau Dispatcher.</p>
<p>Pour notre exemple on partira du principe que l’on a un contrôle nommé Loader qui se charge de l’animation pour faire patienter l’utilisateur.</p>
<p>Commençons par créer un nouveau thread.</p>
<pre class="code"><span style="color: #2b91af">Thread </span>thread = <span style="color: blue">new </span><span style="color: #2b91af">Thread</span>(arg =&gt;
                   {
                       loader = <span style="color: blue">new </span><span style="color: #2b91af">Loader</span>();
                       loader.Topmost = <span style="color: blue">true</span>;
                       loader.ShowInTaskbar = <span style="color: blue">false</span>;
                       loader.Show();

                       System.Windows.Threading.<span style="color: #2b91af">Dispatcher</span>.Run();
                   });
        thread.SetApartmentState(<span style="color: #2b91af">ApartmentState</span>.STA);
        thread.Start();</pre>
<p>Première chose, vous noterez que l’on assigne à ce thread un ApartmentState STA, obligatoire pour fonctionner avec la plupart des composants graphiques. Ce comportement est plus inhérent à Windows qu’à WPF même. Je vous renvoie vers ce lien si vous souhaitez en savoir plus sur le sujet: <a title="http://msdn.microsoft.com/en-us/library/ms680112%28VS.85%29.aspx" href="http://msdn.microsoft.com/en-us/library/ms680112%28VS.85%29.aspx">http://msdn.microsoft.com/en-us/library/ms680112%28VS.85%29.aspx</a></p>
<p>Ensuite nous appelons la méthode start qui comme vous pouvez le constater va se charger de créer une nouvelle instance du Loader, de l’afficher par dessus toutes les autres fenêtres. Ce contrôle est une fenêtre et nous ne souhaitons pas l’afficher dans la barre des tâches.</p>
<p>La dernière ligne “System.Windows.Threading.<span style="color: #2b91af">Dispatcher</span>.Run();” permet de démarrer un nouveau Dispatcher associé à ce thread pour effectuer tout nouveau traitement UI (animations…). </p>
<p>Une fois l’opération sous jacente terminée, il ne vous reste plus qu’à arrêter le dispatcher et le thread associé en appelant la méthode suivante:</p>
<pre class="code">loader.Dispatcher.InvokeShutdown();</pre>
<p>&#160;</p>
<p>Et voilà comment donner à l’utilisateur une sensation de fluidité de l’application</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/10/11/dmarrer-une-animation-sur-un-nouveau-thread-dui/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Afficher un Message de confirmation lors de l&#8217;ex&#233;cution d&#8217;une ICommand</title>
		<link>http://blog.experida.fr/2011/09/20/afficher-un-message-de-confirmation-lors-de-lexcution-dune-icommand/</link>
		<comments>http://blog.experida.fr/2011/09/20/afficher-un-message-de-confirmation-lors-de-lexcution-dune-icommand/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 20:55:54 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[Confirmation]]></category>
		<category><![CDATA[ICommand]]></category>
		<category><![CDATA[MVVM]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/09/20/afficher-un-message-de-confirmation-lors-de-lexcution-dune-icommand/</guid>
		<description><![CDATA[Lorsqu’on utilise le pattern MVVM et les ICommand, il nous arrive régulièrement de vouloir afficher une Message Box de confirmation avant de procéder à l’exécution de la Commande. C’est notamment le cas pour la suppression d’un élément afin d’éviter tout action faite par erreur et non désirée par l’utilisateur. La solution que je vais présenter [...]]]></description>
			<content:encoded><![CDATA[<p>Lorsqu’on utilise le pattern MVVM et les ICommand, il nous arrive régulièrement de vouloir afficher une Message Box de confirmation avant de procéder à l’exécution de la Commande. C’est notamment le cas pour la suppression d’un élément afin d’éviter tout action faite par erreur et non désirée par l’utilisateur.</p>
<p>La solution que je vais présenter dans ce billet n’est en rien LA solution, mais une solution possible que j’utilise dans les projets sur lesquels je travaille.</p>
<p><span id="more-309"></span>
<p>Comme nous souhaitons afficher un message de confirmation, nous avons que deux résultats possibles. </p>
<ul>
<li>Oui je confirme l’action</li>
<li>Ou non on annule l’action</li>
</ul>
<p>A ce titre, notre Commande va prendre en paramètre un délégué de type Func&lt;bool&gt;.</p>
<p>Pour rappel, un délégué de ce type permet d’invoquer une méthode qui ne prend aucun paramètre en entrée, mais possède une valeur de retour de type bool.&#160; Cette valeur de retour sera la réponse suite à l’action de l’utilisateur sur la message box.</p>
<p>Dans la méthode appelée suite à l’exécution de la commande, la seule chose que nous avons à faire est d’invoquer le délégué dans une clause IF afin de savoir si l’on doit continuer ou non.</p>
<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">ICommand </span>DeletePictureCommand
       {
           <span style="color: blue">get
           </span>{
               <span style="color: blue">if </span>(deletePictureCommand == <span style="color: blue">null</span>)
                   deletePictureCommand =
                       <span style="color: blue">new </span><span style="color: #2b91af">DelegateCommand</span>&lt;<span style="color: #2b91af">Func</span>&lt;<span style="color: blue">bool</span>&gt;&gt;(DeletePicture,  (param)  =&gt; <span style="color: blue">true</span>);
               <span style="color: blue">return </span>deletePictureCommand;
           }
       }

       <span style="color: blue">private void </span>DeletePicture(<span style="color: #2b91af">Func</span>&lt;<span style="color: blue">bool</span>&gt; confirmDeletion)
       {

           <span style="color: blue">if </span>(confirmDeletion())
           {

           }
       }</pre>
<p>Côté vue, nous allons créer une petite classe Helper nous permettant:</p>
<ul>
<li>d’indiquer le message à afficher dans la message box.</li>
<li>d’instancier et afficher la message box.</li>
</ul>
<p>Pour cela, commencez par créer une propriété attachée de type string que nous allons nommer ConfirmationMessage.</p>
<pre class="code"><span style="color: blue">public static string </span>GetConfirmationMessage(<span style="color: #2b91af">DependencyObject </span>obj)
        {
            <span style="color: blue">return </span>(<span style="color: blue">string</span>)obj.GetValue(ConfirmationMessageProperty);
        }

        <span style="color: blue">public static void </span>SetConfirmationMessage(<span style="color: #2b91af">DependencyObject </span>obj, <span style="color: blue">string </span>value)
        {
            obj.SetValue(ConfirmationMessageProperty, value);
        }

        <span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>ConfirmationMessageProperty =
            <span style="color: #2b91af">DependencyProperty</span>.RegisterAttached(<span style="color: #a31515">&quot;ConfirmationMessage&quot;</span>, <span style="color: blue">typeof</span>(<span style="color: blue">string</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">CommandConfirmationHelper</span>),
            <span style="color: blue">new </span><span style="color: #2b91af">UIPropertyMetadata</span>(<span style="color: blue">null</span>, <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedCallback</span>(OnConfirmationMessageChanged)));</pre>
<p>&#160;</p>
<p>Puis, ajoutez une méthode pour le PropertyChangedCallback dans laquelle nous allons récupérer la commande que l’on souhaite lier à la message box et à laquelle nous allons passer au CommandParameter un délégué de type Func&lt;bool&gt;, qui comme vous pouvez le voir ci-dessous ne fait que retourner le résultat lié à l’appel de la méthode MessageBox.Show. MessageBox de type “YesNo”</p>
<pre class="code"><span style="color: blue">private static void </span>OnConfirmationMessageChanged(<span style="color: #2b91af">DependencyObject </span>d, <span style="color: #2b91af">DependencyPropertyChangedEventArgs </span>e)
        {
            <span style="color: blue">if </span>(e.NewValue != <span style="color: blue">null</span>)
            {
                <span style="color: #2b91af">ICommandSource </span>commandSource = d <span style="color: blue">as </span><span style="color: #2b91af">ICommandSource</span>;
                <span style="color: blue">string </span>message = e.NewValue.ToString();
                <span style="color: blue">if </span>(commandSource != <span style="color: blue">null</span>)
                {
                    <span style="color: #2b91af">Func</span>&lt;<span style="color: blue">bool</span>&gt; del =
                        () =&gt; { <span style="color: blue">return </span><span style="color: #2b91af">MessageBox</span>.Show(message, <span style="color: #a31515">&quot;Titre&quot;</span>, <span style="color: #2b91af">MessageBoxButton</span>.YesNo) == <span style="color: #2b91af">MessageBoxResult</span>.Yes; };
                    <span style="color: #2b91af">Type </span>type = d.GetType();
                    <span style="color: #2b91af">PropertyInfo </span>pinfo = type.GetProperty(<span style="color: #a31515">&quot;CommandParameter&quot;</span>);
                    pinfo.SetValue(d, del, <span style="color: blue">null</span>);
                }
            }
        }</pre>
<p>&#160;</p>
<p>La dernière chose qu’il nous reste à faire est de mettre à jour le code xaml en y ajoutant une référence à la propriété attachée sur l’élément possédant la commande à exécuter,:</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ListView.InputBindings</span><span style="color: blue">&gt;
     &lt;</span><span style="color: #a31515">KeyBinding </span><span style="color: red">Key</span><span style="color: blue">=&quot;Delete&quot;                           </span><span style="color: red"> uihelper</span><span style="color: blue">:</span><span style="color: red">CommandConfirmationHelper.ConfirmationMessage</span><span style="color: blue">=&quot;Etes-vous sûr de vouloir supprimer la photo ?&quot;
</span><span style="color: red">  Command</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">Binding </span><span style="color: red">DeletePictureCommand</span><span style="color: blue">}&quot;  /&gt;
&lt;/</span><span style="color: #a31515">ListView.InputBindings</span><span style="color: blue">&gt;
</span></pre>
<p>&#160;</p>
<p>Et voilà rien de bien compliqué, mais plutôt pratique et simple à mettre en place.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/09/20/afficher-un-message-de-confirmation-lors-de-lexcution-dune-icommand/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Acc&#232;s &#224; l&#8217;IsolatedStorage depuis des applications diff&#233;rentes d&#8217;un m&#234;me site</title>
		<link>http://blog.experida.fr/2011/05/16/accs-lisolatedstorage-depuis-des-applications-diffrentes-dun-mme-site/</link>
		<comments>http://blog.experida.fr/2011/05/16/accs-lisolatedstorage-depuis-des-applications-diffrentes-dun-mme-site/#comments</comments>
		<pubDate>Mon, 16 May 2011 21:10:28 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[ApplicationSettings]]></category>
		<category><![CDATA[IsolatedStorage]]></category>
		<category><![CDATA[Silverlight 4]]></category>
		<category><![CDATA[SiteSettings]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/05/16/accs-lisolatedstorage-depuis-des-applications-diffrentes-dun-mme-site/</guid>
		<description><![CDATA[Récemment j’ai eu le besoin de partager des informations entre différentes applications Silverlight qui étaient hébergées sur le même site. Par même site il faut comprendre accessibles depuis le même sous domaine. Prenons un exemple. Deux applications disponibles de la manière suivante: Application 1: http://mondomain.com/App1 Application 2: http://mondomain.com/App2 Chacune des applications se trouvant aux Urls [...]]]></description>
			<content:encoded><![CDATA[<p>Récemment j’ai eu le besoin de partager des informations entre différentes applications Silverlight qui étaient hébergées sur le même site. Par même site il faut comprendre accessibles depuis le même sous domaine.</p>
<p>Prenons un exemple.</p>
<p>Deux applications disponibles de la manière suivante:</p>
<ul>
<li>Application 1: <a href="http://mondomain.com/App1">http://mondomain.com/App1</a> </li>
<li>Application 2: h<a href="http://mondomain.com/App2">ttp://mondomain.com/App2</a> </li>
</ul>
<p>Chacune des applications se trouvant aux Urls ci-dessus ont un espace de stockage dédié à l’application. Il est possible d’y ajouter ou modifier des éléments à partir d’ApplicationSettings.</p>
<pre class="code"><span style="color: #2b91af">IsolatedStorageSettings</span>.ApplicationSettings.Add(<span style="color: #a31515">&quot;key&quot;</span>, <span style="color: #a31515">&quot;value&quot;</span>);</pre>
<p>Maintenant pour avoir un espace partagé entre les applications xap des sites App1 et App2, il vous suffit simplement d’accéder à l’IsolatedStorage via SiteSettings se trouvant également dans IsolatedStorageSettings.</p>
<pre class="code"><span style="color: #2b91af">IsolatedStorageSettings</span>.SiteSettings.Add(<span style="color: #a31515">&quot;key&quot;</span>, <span style="color: #a31515">&quot;value&quot;</span>);</pre>
<p>Rien de bien compliqué, mais plutôt pratique !!</p>
<p>La méthode que nous venons de voir correspond à un raccourci pour obtenir le contenu des différents stores. Pour une plus grande souplesse vous pouvez accéder à ces stores via les méthodes</p>
<ul>
<pre class="code"><span style="color: #2b91af">IsolatedStorageFile</span>.GetUserStoreForApplication();
<span style="color: #2b91af">IsolatedStorageFile</span>.GetUserStoreForSite();</pre>
<p>A partir de là, vous pourrez par exemple créer une arborescence, connaitre l’espace utilisé et restant, agrandir l’espace courant pour stoker un nombre de données plus important…</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/05/16/accs-lisolatedstorage-depuis-des-applications-diffrentes-dun-mme-site/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MEF- AppSettings Catalog</title>
		<link>http://blog.experida.fr/2011/03/29/mef-appsettings-catalog/</link>
		<comments>http://blog.experida.fr/2011/03/29/mef-appsettings-catalog/#comments</comments>
		<pubDate>Mon, 28 Mar 2011 22:41:58 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[mef]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[AppSettingsCatalog]]></category>
		<category><![CDATA[ComposablePartDefinition]]></category>
		<category><![CDATA[MEF; ComposablePart]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/03/29/mef-appsettings-catalog/</guid>
		<description><![CDATA[Si vous avez lu les précédents billets, vous aurez remarqué que ces derniers parlent de situations rencontrées lors de ma mission actuelle. Ce sera encore le cas pour ce billet, où nous allons voir comment créer un catalogue basé sur les AppSettings du fichier de configuration. Besoin: Dans cette application, nous avons un service d’authentification [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Si vous avez lu les précédents billets, vous aurez remarqué que ces derniers parlent de situations rencontrées lors de ma mission actuelle. Ce sera encore le cas pour ce billet, où nous allons voir comment créer un catalogue basé sur les AppSettings du fichier de configuration.</p>
<p align="justify"><u>Besoin:</u></p>
<p align="justify">Dans cette application, nous avons un service d’authentification qui selon certains critères peut choisir tel ou tel module pour authentifier l’utilisateur. La résolution du module en question est faite via MEF. Ce module peut avoir besoin de paramètres comme par exemple l’url d’un Web Service et l’environnement sur lequel on souhaite réaliser cette opération.</p>
<p align="justify">Plutôt que de toujours faire appel à ConfigurationManager.AppSettings[key] dans le module lui-même je souhaitais trouver un moyen d’injecter ces valeurs. Ceci est notamment possible avec MEF, c’est ce que nous allons voir tout de suite.</p>
<div align="justify"><span id="more-293"></span></div>
<p align="justify">Si vous avez déjà utilisé MEF, vous savez que ce Framework fonctionne avec les attributs Export et Import. Chaque ComposablePart exporte et importe des services vers ou provenant d’autres ComposableParts. Dans le cas de AppSettings, il faut voir une paire de Key/Value comme une ComposablePart qui va nous permettre de créer une part(la valeur) à partir d’un contrat la key.</p>
<p align="justify">Généralement, les parts sont reliées entre elles via des contrats de type interface ou classe de base, permettant de faciliter le découplage du code. Si aucun contrat n’est spécifié, MEF va se baser sur le type du service Exporté ou Importé.</p>
<p align="justify"><u>Prenons pour exemple la classe suivante:</u></p>
<p align="justify">Ajoutez une classe nommée “MainPart”, contenant deux propriétés, P1 et P2. Pour indiquer que MainPart est une Part, ajoutez lui un attribut Export, puis ajoutez un attribut Import sur chacune des propriétés pour dire qu’on attend que MEF fasse également la résolution de ces deux propriétés / part pour utiliser la classe MainPart.</p>
<div align="justify">
<pre class="code">   [<span style="color: #2b91af">Export</span>]
   <span style="color: blue">public class </span><span style="color: #2b91af">MainPart
   </span>{
       [<span style="color: #2b91af">Import</span>(<span style="color: #a31515">&quot;AppSettingsKey&quot;</span>)]
       <span style="color: blue">public string </span>P1 { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

       [<span style="color: #2b91af">Import</span>(<span style="color: #a31515">&quot;AppSettingsKey2&quot;</span>)]
       <span style="color: blue">public string </span>P2 { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
   }</pre>
</div>
<p align="justify">Dans le code ci-dessus, vous pouvez voir que pour l’export, nous n’avons rien spécifié, le contrat sera donc le nom complet de MainPart: namespace + nom de la classe. Pour P1 et P2, nous ajoutons manuellement un contrat sous forme de string. Le conteneur s’appuiera sur ces valeurs “AppSettingsKey” et “AppSettingsKey2” pour récupérer la valeur.</p>
<p align="justify">Voyons maintenant un peu plus en détail comment créer notre catalogue personnalisé</p>
<p align="justify">Première étape à réaliser, la création du catalogue que nous nommerons AppSettingsCatalog.</p>
<p align="justify">AppSettingsCatalog doit hériter de ComposablePartCatalog. Le but du catalogue est de fournir une “vue” au conteneur MEF, des différents Export disponibles. Le catalogue ne créé par les parts, il ne fait que fournir une définition des parts au travers de la méthode Parts de type IQueryable&lt;ComposablePartDefinition&gt;.</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">AppSettingsCatalog </span>: <span style="color: #2b91af">ComposablePartCatalog
   </span>{
       <span style="color: blue">public override </span><span style="color: #2b91af">IQueryable</span>&lt;<span style="color: #2b91af">ComposablePartDefinition</span>&gt; Parts
       {
           <span style="color: blue">get
           </span>{
               <span style="color: blue">return </span>(<span style="color: blue">from </span>k <span style="color: blue">in </span><span style="color: #2b91af">ConfigurationManager</span>.AppSettings.AllKeys
                       <span style="color: blue">select </span>(<span style="color: #2b91af">ComposablePartDefinition</span>)
                           <span style="color: blue">new </span><span style="color: #2b91af">AppSettingsPartDefinition </span>{ Key = k })
                      .AsQueryable&lt;<span style="color: #2b91af">ComposablePartDefinition</span>&gt;();
           }
       }
   }</pre>
</p>
<p align="justify">Dans le code ci-dessus, on voit par exemple que la méthode Parts donne des AppSettingsPartDefinition à laquelle on passe à chaque fois une clé de AppSettings.</p>
<p align="justify">Comme vous l’aurez deviné, la deuxième étape est donc de construire la classe AppSettingPartDefinition. A nouveau cette classe hérite d’une classe parente nommée ComposablePartDefinition. </p>
<p align="justify">Le but de cette classe est double: créer une ComposablePart qui se chargera de créer la Part et fournir une description de l’ensemble des contrats que la part peut donner ou utiliser. Il faut voir cet élément un peu comme un élément descriptif / un type au sens Type.</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">AppSettingsPartDefinition </span>: <span style="color: #2b91af">ComposablePartDefinition
</span>{

    <span style="color: blue">private string </span>key;

    <span style="color: blue">public </span>AppSettingsPartDefinition()
    { }

    <span style="color: blue">public string </span>Key
    {

        <span style="color: blue">get </span>{ <span style="color: blue">return this</span>.key; }
        <span style="color: blue">set </span>{ <span style="color: blue">this</span>.key = <span style="color: blue">value</span>; }

    }

    <span style="color: blue">public override </span><span style="color: #2b91af">ComposablePart </span>CreatePart()
    {
        <span style="color: blue">return new </span><span style="color: #2b91af">AppSettingsComposablePart</span>(<span style="color: blue">this</span>);
    }

    <span style="color: blue">public override </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">ExportDefinition</span>&gt; ExportDefinitions
    {
        <span style="color: blue">get
        </span>{
            <span style="color: blue">var </span>metadata = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: blue">object</span>&gt;();
            metadata.Add(<span style="color: #a31515">&quot;ExportTypeIdentity&quot;</span>, <span style="color: blue">typeof</span>(<span style="color: blue">string</span>).FullName);
            <span style="color: blue">return new</span>[]
                {
                   <span style="color: blue">new </span><span style="color: #2b91af">ExportDefinition</span>(<span style="color: blue">this</span>.key, metadata)
                };
        }
    }

    <span style="color: blue">public override </span>.<span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">ImportDefinition</span>&gt; ImportDefinitions
    {
        <span style="color: blue">get
        </span>{
            <span style="color: blue">return new </span><span style="color: #2b91af">ImportDefinition</span>[0];
        }
    }
}</pre>
<p>On peut voir que la ComposablePart est créée via la méthode CreatePart. ExportDefinitions et ImportDefinitions liste les différents contrats de la Part. On notera également, que pour chaque key on créé un Export avec un contrat dont le nom est représenté par la key.</p>
<p>Dernier élément qu’il nous reste à voir la classe AppSettingsComposablePart. C’est cette classe qui sera chargée d’instancier l’export et de fournir le résultat via la méthode GetExportedValue.</p>
<pre class="code"><span style="color: blue">public override object </span>GetExportedValue(<span style="color: #2b91af">ExportDefinition </span>definition)
{
            <span style="color: blue">return </span><span style="color: #2b91af">ConfigurationManager</span>.AppSettings[definition.ContractName];
}</pre>
<p>ExportDefinition contient notamment l’information sur le nom du contrat. Il nous reste alors plus qu’à passer ce nom de contrat à la propriété AppSettings du ConfigurationManager pour récupérer le résultat. Dans notre exemple la méthode GetExportedValue ne sera appelée qu’une seule fois pour chaque Part, la part ne contenant pas elle même d’autres exports.</p>
<p>Enfin il ne vous reste plus qu’à configurer le conteneur MEF pour utiliser ce nouveau&#160; catalogue et faire la résolution de l’élément MainPart.</p>
<p><u>Fichier de configuration:</u></p>
<pre class="code">  <span style="color: blue">&lt;</span><span style="color: #a31515">appSettings</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">add </span><span style="color: red">key</span><span style="color: blue">=</span>&quot;<span style="color: blue">AppSettingsKey</span>&quot; <span style="color: red">value</span><span style="color: blue">=</span>&quot;<span style="color: blue">AppSettingValue</span>&quot;<span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">add </span><span style="color: red">key</span><span style="color: blue">=</span>&quot;<span style="color: blue">AppSettingsKey2</span>&quot; <span style="color: red">value</span><span style="color: blue">=</span>&quot;<span style="color: blue">AppSettingValue2</span>&quot;<span style="color: blue">/&gt;
  &lt;/</span><span style="color: #a31515">appSettings</span><span style="color: blue">&gt;
</span></pre>
<p>&#160;</p>
<p><u>Configuration du conteneur:</u></p>
<pre class="code"><span style="color: blue">var </span>confCatalog = <span style="color: blue">new </span><span style="color: #2b91af">AppSettingsCatalog</span>();
<span style="color: blue">var </span>typeCatalog = <span style="color: blue">new </span><span style="color: #2b91af">TypeCatalog</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">MainPart</span>));
<span style="color: blue">var </span>aggCatalog = <span style="color: blue">new </span><span style="color: #2b91af">AggregateCatalog</span>(confCatalog, typeCatalog);
<span style="color: blue">var </span>container = <span style="color: blue">new </span><span style="color: #2b91af">CompositionContainer</span>(aggCatalog);</pre>
<p><u>Résolution de MainPart:</u></p>
<pre class="code"><span style="color: blue">var </span>exportedPart = container.GetExport&lt;<span style="color: #2b91af">MainPart</span>&gt;().Value;</pre>
<p>&#160;</p>
<p>Le code de démonstration est disponible <a href="http://blog.experida.fr/wp-content/uploads/2011/03/ComposablePart.zip" target="_blank">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/03/29/mef-appsettings-catalog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 3 et 4 / MEF: dur&#233;e de vie du ViewModel</title>
		<link>http://blog.experida.fr/2011/03/12/silverlight-3-mef-et-dispose-des-ressources/</link>
		<comments>http://blog.experida.fr/2011/03/12/silverlight-3-mef-et-dispose-des-ressources/#comments</comments>
		<pubDate>Sat, 12 Mar 2011 14:54:43 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/03/12/silverlight-3-mef-et-dispose-des-ressources/</guid>
		<description><![CDATA[Dans le cadre de ma mission, je développe en ce moment une application utilisant Silverlight. Nous avons décidé d’appliquer le pattern MVVM. Pour chaque page, nous avons donc un ViewModel assigné au DataContext, dans lequel sont injectés différents services nécessaires à nos besoins. Pré-requis de l’application: Utilisation de MEF, pour faire la résolution des ViewModels [...]]]></description>
			<content:encoded><![CDATA[<p>Dans le cadre de ma mission, je développe en ce moment une application utilisant Silverlight.  Nous avons décidé d’appliquer le pattern MVVM. Pour chaque page, nous avons donc un ViewModel assigné au DataContext, dans lequel sont injectés différents services nécessaires à nos besoins.</p>
<p>Pré-requis de l’application:</p>
<ul>
<li>
<div>Utilisation de MEF, pour faire la résolution des ViewModels et de leurs services.</div>
</li>
<li>
<div>Lorsque l’on navigue sur une nouvelle page, celle-ci doit être dans le même état que lors du premier accès.</div>
</li>
</ul>
<p><span id="more-286"></span></p>
<ul></ul>
<p>Afin de respecter ces deux points, nous avons commencé par créer un CompositionContainer MEF avec un DeployementCatalog pour la découverte des différentes Parts. Le catalogue contient donc toutes les parts du xap courant, peu importe la policy: Shared et NonShared.</p>
<p><span style="text-decoration: underline;"><strong>Cas de Silverlight 3:</strong></span></p>
<p><strong>Tests effectués avec la version de MEF (preview 9) présente sur codeplex.</strong></p>
<p>Silverlight 3 intègre un système de navigation par page. Mais dans cette version, nous ne pouvons pas intervenir sur la création d’une page. Chaque page est donc créée par le PageResourceContentLoader.  Pour faire la résolution du ViewModel, disponible sur chaque page au travers d’un Import, nous devons pouvoir accéder au conteneur directement depuis la page. Pour cela,  j’ai créé une classe App qui est une classe statique. Elle contient une propriété également statique et de type Composition Container qui permet de créer le conteneur principal si il n’existe pas encore puis de le retourner.</p>
<p><span style="color: #2b91af;">App.Container.</span>SatisfyImportsOnce(<span style="color: blue;">this</span>)</p>
<p>A chaque changement de page, une nouvelle page est instanciée et le temps que la méthode SatisfyImportsOnce n’est pas appelée, le ViewModel est null. Pour remplir la seconde condition donnée plus haut dans les pré-requis, nous avons fait le choix de demander à MEF de nous donner une nouvelle instance à chaque fois. L’export d’un ViewModel est assigné à NonShared pour la CreationPolicy. Pour rappel lorsque l’on associe une policy NonShared  à un export, une instance différente sera donnée pour chaque Import. (Attention, pour avoir toujours une instance différente sur un import d’une même instance, regardez du côté d’ExportFactory). Comme dans notre cas, une nouvelle page est créée à chaque fois, il n’y aura pas de problème une nouvelle instance sera utilisée pour la propriété ViewModel.</p>
<p>D’après la documentation, le conteneur MEF ne tient pas de référence entre une part NonShared et le conteneur chargé de sa création. Cependant après une navigation continue dans l’application, j’ai pu constater que la mémoire montait. Avec l’aide d’un profiler, on se rend compte que les différentes instances de ViewModel créées continuent d’éxister, malgré le fait qu’elles ne soient plus référencées par d’autres objets, du moins cela devrait être le cas. Sauf qu’en y regardant d’un peu plus près, le profiler nous indique clairement, qu’il y a une référence du conteneur et plus précisément de ReflectionComposablePart sur chaque ViewModel. Ils ne peuvent donc pas être pris par le Garbage Collector.</p>
<p>Après quelques recherches supplémentaires, il semblerait qu’il y ait un bug avec cette version.</p>
<p>Pour le contourner et ne pas provoquer de problème mémoire, voici une solution possible:</p>
<p>La création d’un conteneur enfant. L’idée est d’avoir un conteneur MEF global à l’application et pouvant faire la résolution  de toutes les parts, qu’il s’agisse d’un Export type NonShared ou Shared. Pour une requête vers une page, on créé un conteneur enfant qui prend un catalogue filtré avec seulement les Parts ayant une policy NonShared. C’est ce conteneur qui fera la résolution du ViewModel.</p>
<p>Lors du changement de page, il suffit de faire un dispose du conteneur enfant. Toutes les parts créées par ce contenur seront alors supprimées. Si un ViewModel implémente l’interface IDisposable, la méthode Dispose sera également appelée.</p>
<pre class="code"><span style="color: #2b91af;">CompositionContainer </span>rootContainer = App.Container <span style="color: blue;">as </span><span style="color: #2b91af;">CompositionContainer</span>;
<span style="color: #2b91af;">FilteredCatalog </span>cat = <span style="color: blue;">new </span><span style="color: #2b91af;">FilteredCatalog</span>(rootContainer.Catalog,
p =&gt;
 p.Metadata.ContainsKey(<span style="color: #2b91af;">CompositionConstants</span>.PartCreationPolicyMetadataName)
  &amp;&amp;
   ((<span style="color: #2b91af;">CreationPolicy</span>)p.Metadata[<span style="color: #2b91af;">CompositionConstants
      </span>.PartCreationPolicyMetadataName])  == <span style="color: #2b91af;">CreationPolicy</span>.NonShared);
child = <span style="color: blue;">new </span><span style="color: #2b91af;">CompositionContainer</span>(cat, rootContainer);
child.SatisfyImportsOnce(<span style="color: blue;">this</span>);</pre>
<p><span style="text-decoration: underline;"><strong>Cas de Silverlight 4:</strong></span></p>
<p>Pour effectuer le test avec Silverlight 4, j’ai simplement changé la version utilisée par mes applications et librairies Silverlight en les passant à la version 4, puis j’ai supprimé les références pointant vers les dll du MEF de codeplex pour ajouter celles qui sont natives au framework 4. Vous pouvez également supprimer le conteneur enfant.</p>
<p>Pour que le test soit similaire à celui effectué avec la version 3, j’accède toujours au conteneur depuis la page pour faire la résolution du ViewModel, mais sachez que vous avez la possibilité d’instancier la page via MEF en créant votre propre ContentLoader. Le ViewModel serait alors automatiquement résolu.</p>
<p>Notez qu’à chaque changement de page nous appelons également GC.Collect pour forcer le garbage collector à collecter les objets si ils sont disponibles.</p>
<p>Il suffit ensuite de regarder le profiler pour voir que les parts sont bien supprimées.</p>
<p><span style="text-decoration: underline;">Résultat du profiler lors de la navigation vers la homepage:</span></p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2011/03/image.png"><img title="image" src="http://blog.experida.fr/wp-content/uploads/2011/03/image_thumb.png" alt="image" style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" border="0" width="501" height="86" /></a></p>
<p><span style="text-decoration: underline;">Résultat du profiler lors de la navigation de homepage vers une autre page sans ViewModel associé:</span></p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2011/03/image1.png"><img title="image" src="http://blog.experida.fr/wp-content/uploads/2011/03/image_thumb1.png" alt="image" style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" border="0" width="504" height="84" /></a></p>
<p>On peut constater que les instances ne sont plus présentes.</p>
<p><span style="text-decoration: underline;">Remarque:</span></p>
<p>1- Si vous d</p>
<div class="wlWriterEditableSmartContent" style="margin: 0px; display: inline; float: none; padding: 0px;" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0631b7ac-520a-4ec2-bf65-1488cb34f49c">Technorati Tags: <a href="http://technorati.com/tags/MEF" rel="tag">MEF</a>,<a href="http://technorati.com/tags/Silverlight+3+et+4" rel="tag">Silverlight 3 et 4</a>,<a href="http://technorati.com/tags/ViewModel" rel="tag">ViewModel</a>,<a href="http://technorati.com/tags/Part+LifeTime" rel="tag">Part LifeTime</a></div>
<p>écidez de passer votre ViewModel  avec une CreationPolicy à Shared, il y aura un lien fort entre le conteneur et l’instance du ViewModel. Ce dernier ne sera détruit que lorsque le conteneur sera également détruit.</p>
<p>2- Si votre ViewModel utilise des ressources non managées et que vous implémentez la l’interface IDisposable, le conteneur MEF gardera également une référence vers l’instance. Pour la détruire avant que le conteneur ne soit détruit, vous pouvez par exemple utiliser la méthode ReleaseExport du conteneur.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/03/12/silverlight-3-mef-et-dispose-des-ressources/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight &#8211; D&#233;veloppement d&#8217;un expander</title>
		<link>http://blog.experida.fr/2011/02/11/silverlight-developpement-dun-expander/</link>
		<comments>http://blog.experida.fr/2011/02/11/silverlight-developpement-dun-expander/#comments</comments>
		<pubDate>Thu, 10 Feb 2011 22:45:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[expander]]></category>
		<category><![CDATA[Style]]></category>
		<category><![CDATA[Template]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/02/11/silverlight-developpement-dun-expander/</guid>
		<description><![CDATA[Dans un projet récent, j&#8217;avais besoin de masquer certaines parties de la page. Je sais qu&#8217;il existe dans des librairies tierces des contrôles permettant de déjà réaliser cette opération. Cependant, il y a certains projets, où il est impossible d&#8217;utiliser ces librairies. Ce que je vous propose dans ce billet c&#8217;est donc d&#8217;en développer un [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Dans un projet récent, j&#8217;avais besoin de masquer certaines parties de la page. Je sais qu&#8217;il existe dans des librairies tierces des contrôles permettant de déjà réaliser cette opération. Cependant, il y a certains projets, où il est impossible d&#8217;utiliser ces librairies.</p>
<p align="justify">Ce que je vous propose dans ce billet c&#8217;est donc d&#8217;en développer un simple. </p>
<p align="justify">A quoi doit-il ressembler ?</p>
<p align="justify">Graphiquement, il sera composé de quatre parties:</p>
<ul>
<li>
<div align="justify">une partie header pour afficher une description de la partie en question.</div>
</li>
<li>
<div align="justify">un bouton au niveau du header pour activer l&#8217;animation permettant de masquer ou afficher le contenu.</div>
</li>
<li>
<div align="justify">une partie dans laquelle se trouvera le&#160; contenu à masquer ou à afficher.</div>
</li>
<li>
<div align="justify">Et un séparateur entre le header et le contenu à afficher.</div>
</li>
</ul>
<p align="justify">Allez démarrons&#8230;</p>
<div align="justify"><span id="more-279"></span></div>
<p align="justify">Ouvrez votre Visual Studio et ajoutez un nouvel item basé sur le type &quot;Silverlight Templated&#160; Control&quot;. Vous devriez maintenant avoir un fichier cs et un dossier Themes contenant un fichier generic.xaml</p>
<p align="justify">Commençons par éditer le generic.xaml pour définir le style de notre contrôle et en particulier la propriété Template.</p>
<ul>
<li>
<div align="justify">Pour le header ajoutons un simple TextBlock. Pas besoin de faire bien compliqué un simple texte décrivant le contenu suffira.</div>
</li>
<li>
<div align="justify">Pour le séparateur, mettons un rectangle, nous y associerons ensuite un Style pour indiquer la couleur, la hauteur&#8230;</div>
</li>
<li>
<div align="justify">Pour le bouton chargé de l&#8217;animation pour masquer le contenu, utilisons un ToggleButton. Nous verrons un peu plus loin pourquoi j&#8217;ai fais ce choix.</div>
</li>
<li>
<div align="justify">Enfin pour que l&#8217;utilisateur utilisant ce contrôle puisse définir le contenu sur lequel agir, ajoutons un ContentPresenter. </div>
</li>
</ul>
<div align="justify">
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Template&quot;&gt;
            &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ControlTemplate </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;local:Expander&quot;&gt;
                    &lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">Grid </span><span style="color: blue">&gt;
                            &lt;</span><span style="color: #a31515">Grid.RowDefinitions</span><span style="color: blue">&gt;
                                &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: blue">/&gt;
                                &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">Height</span><span style="color: blue">=&quot;2&quot; /&gt;
                                &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;row&quot;  </span><span style="color: red">Height</span><span style="color: blue">=&quot;*&quot; /&gt;
                            &lt;/</span><span style="color: #a31515">Grid.RowDefinitions</span><span style="color: blue">&gt;
                            &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">TemplateBinding </span><span style="color: red">HeaderText</span><span style="color: blue">}&quot;/&gt;
                            &lt;</span><span style="color: #a31515">Rectangle
                                 </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Stretch&quot;
                                </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;1&quot;
                                </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Hr&quot;
                                </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Top&quot;
                                /&gt;
                            &lt;</span><span style="color: #a31515">Grid </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;2&quot;
                                </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;ContentGrid&quot;
                                </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Stretch&quot;
                                </span><span style="color: red">RenderTransformOrigin</span><span style="color: blue">=&quot;0.5,0.0&quot;&gt;
                                &lt;</span><span style="color: #a31515">Grid.RenderTransform</span><span style="color: blue">&gt;
                                    &lt;</span><span style="color: #a31515">TransformGroup</span><span style="color: blue">&gt;
                                        &lt;</span><span style="color: #a31515">ScaleTransform </span><span style="color: red">ScaleY</span><span style="color: blue">=&quot;1&quot;/&gt;
                                    &lt;/</span><span style="color: #a31515">TransformGroup</span><span style="color: blue">&gt;
                                &lt;/</span><span style="color: #a31515">Grid.RenderTransform</span><span style="color: blue">&gt;
                                &lt;</span><span style="color: #a31515">ContentPresenter </span><span style="color: red">Margin</span><span style="color: blue">=&quot;0,20,0,0&quot;/&gt;
                            &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">ToggleButton
                            </span><span style="color: red">Grid.RowSpan</span><span style="color: blue">=&quot;2&quot;
                            </span><span style="color: red">IsThreeState</span><span style="color: blue">=&quot;False&quot;
                            </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;ToggleButton_Part&quot;
                            </span><span style="color: red">Cursor</span><span style="color: blue">=&quot;Hand&quot;
                            </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;1&quot;
                            </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Top&quot;
                            </span><span style="color: red">Margin</span><span style="color: blue">=&quot;0,0,-25,0&quot;
                            </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Right&quot;
                            /&gt;
                    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">ControlTemplate</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Comme vous l&#8217;aurez compris en voyant le ContentPresenter, notre contrôle expander hérite de ContentControl.</p>
<p align="justify">Maintenant, ouvrez le fichier cs, nous allons y ajouter quelques propriétés de type DependencyProperty et méthodes pour modifier son comportement de base.</p>
<p align="justify">La première propriété sera IsOpen de type boolean. Sa valeur par défaut sera à true, pour indiquer que lors du premier affichage le contenu doit être visible. Lors de la création d&#8217;une DependencyProperty, on a également la possibilité d&#8217;ajouter un callback, afin que lors du changement de la valeur on puisse effectuer une opération supplémentaire. Dans notre cas nous allons simplement appeler la méthode GoToState du VisualStateManager.&#160; Cette méthode prend notamment en paramètre le nom du nouvel état visuel dans lequel le contrôle doit se trouver.</p>
<div align="justify">
<pre class="code"><span style="color: blue">public bool </span>IsOpen
{
  <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: blue">bool</span>)GetValue(IsOpenProperty); }
  <span style="color: blue">set </span>{ SetValue(IsOpenProperty, <span style="color: blue">value</span>); }
}

<span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>IsOpenProperty =
    <span style="color: #2b91af">DependencyProperty</span>.Register(
    <span style="color: #a31515">&quot;IsOpen&quot;</span>,
    <span style="color: blue">typeof</span>(<span style="color: blue">bool</span>),
    <span style="color: blue">typeof</span>(<span style="color: #2b91af">Expander</span>),
    <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(<span style="color: blue">true</span>,
    <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedCallback</span>(IsOpenChangedCallback)));

<span style="color: blue">static void </span>IsOpenChangedCallback(<span style="color: #2b91af">DependencyObject </span>d,
      <span style="color: #2b91af">DependencyPropertyChangedEventArgs </span>e)
{
  <span style="color: #2b91af">Expander </span>exp = d <span style="color: blue">as </span><span style="color: #2b91af">Expander</span>;
  <span style="color: blue">if </span>(exp != <span style="color: blue">null</span>)
       exp.IsOpenChanged(e);
}

<span style="color: blue">public virtual void </span>IsOpenChanged(<span style="color: #2b91af">DependencyPropertyChangedEventArgs </span>e)
{
   <span style="color: blue">if </span>(IsOpen)
       <span style="color: #2b91af">VisualStateManager</span>.GoToState(<span style="color: blue">this</span>, <span style="color: #2b91af">Expander</span>.ExpandedState, <span style="color: blue">false</span>);
    <span style="color: blue">else
       </span><span style="color: #2b91af">VisualStateManager</span>.GoToState(<span style="color: blue">this</span>, <span style="color: #2b91af">Expander</span>.CollapsedState, <span style="color: blue">false</span>);
}</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">ExpandedState et CollpasedState sont deux constantes de type string contenant le nom de l&#8217;état que nous allons déclarer dans le generic.xaml.</p>
<div align="justify">
<pre class="code"><span style="color: blue">private const string </span>ExpandedState = <span style="color: #a31515">&quot;Expanded&quot;</span>;
<span style="color: blue">private const string </span>CollapsedState = <span style="color: #a31515">&quot;Collapsed&quot;</span>;</pre>
</div>
<p align="justify">Avant d&#8217;ajouter de nouvelles propriétés, modifions le generic.xaml pour ajouter les VisualStates correspondant à ExpandedState et CollpasedState. Un VisualState c&#8217;est ni plus ni moins qu&#8217;une Storyboard permettant de définir une animation sur notre contrôle.</p>
<div align="justify">
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">VisualStateManager.VisualStateGroups</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">VisualStateGroup </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;OpenStates&quot;&gt;
    &lt;</span><span style="color: #a31515">VisualState </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Expanded&quot;&gt;
      &lt;</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
         &lt;</span><span style="color: #a31515">DoubleAnimation </span><span style="color: red">Storyboard.TargetName</span><span style="color: blue">=&quot;ContentGrid&quot;
            </span><span style="color: red">Storyboard.TargetProperty</span><span style="color: blue">=&quot;(UIElement.RenderTransform)
                   .(TransformGroup.Children)[0].(ScaleTransform.ScaleY)&quot;
            </span><span style="color: red">To</span><span style="color: blue">=&quot;1&quot; </span><span style="color: red">Duration</span><span style="color: blue">=&quot;0:0:0.3&quot;&gt;
              &lt;</span><span style="color: #a31515">DoubleAnimation.EasingFunction</span><span style="color: blue">&gt;
                  &lt;</span><span style="color: #a31515">ExponentialEase </span><span style="color: red">EasingMode</span><span style="color: blue">=&quot;EaseOut&quot;
                      </span><span style="color: red">Exponent</span><span style="color: blue">=&quot;4&quot; /&gt;
              &lt;/</span><span style="color: #a31515">DoubleAnimation.EasingFunction</span><span style="color: blue">&gt;
          &lt;/</span><span style="color: #a31515">DoubleAnimation</span><span style="color: blue">&gt;
      &lt;/</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">VisualState</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">VisualState </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Collapsed&quot;&gt;
      &lt;</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">DoubleAnimation </span><span style="color: red">Storyboard.TargetName</span><span style="color: blue">=&quot;ContentGrid&quot;
           </span><span style="color: red">Storyboard.TargetProperty</span><span style="color: blue">=&quot;(UIElement.RenderTransform)
             .(TransformGroup.Children)[0].(ScaleTransform.ScaleY)&quot;
           </span><span style="color: red">To</span><span style="color: blue">=&quot;0&quot; </span><span style="color: red">Duration</span><span style="color: blue">=&quot;0:0:0.3&quot;&gt;
        &lt;/</span><span style="color: #a31515">DoubleAnimation</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ObjectAnimationUsingKeyFrames
               </span><span style="color: red">BeginTime</span><span style="color: blue">=&quot;0:0:0.3&quot;
               </span><span style="color: red">Duration</span><span style="color: blue">=&quot;0&quot;
               </span><span style="color: red">Storyboard.TargetName</span><span style="color: blue">=&quot;row&quot;
              </span><span style="color: red"> Storyboard.TargetProperty</span><span style="color: blue">=&quot;Height&quot;&gt;
               &lt;</span><span style="color: #a31515">DiscreteObjectKeyFrame </span><span style="color: red">KeyTime</span><span style="color: blue">=&quot;0&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;0&quot;/&gt;
        &lt;/</span><span style="color: #a31515">ObjectAnimationUsingKeyFrames</span><span style="color: blue">&gt;
     &lt;/</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">VisualState</span><span style="color: blue">&gt;
 &lt;/</span><span style="color: #a31515">VisualStateGroup</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">VisualStateManager.VisualStateGroups</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Reprenons les deux VisualStates:</p>
<ul>
<li>
<div align="justify">Dans Expanded, notre storyboard agit sur le contrôle avec le name ContentGrid. Comme son nom l&#8217;indique il s&#8217;agit du conteneur dans lequel se trouve le ContentPresenter. Nous passons à 1 sa propriété ScaleTransform.ScaleY. Si vous regardez dans le code xaml ajouté plus haut, vous aurez certainement observé qu&#8217;on avait initialisé le grid avec une transformation. La valeur était à 1. Ici nous remettons l&#8217;élément à la même échelle qu&#8217;au départ.</div>
</li>
</ul>
<blockquote>
<div align="justify">
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;2&quot;
   </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;ContentGrid&quot;
   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Stretch&quot;
   </span><span style="color: red">RenderTransformOrigin</span><span style="color: blue">=&quot;0.5,0.0&quot;&gt;
   &lt;</span><span style="color: #a31515">Grid.RenderTransform</span><span style="color: blue">&gt;
     &lt;</span><span style="color: #a31515">TransformGroup</span><span style="color: blue">&gt;
          &lt;</span><span style="color: #a31515">ScaleTransform </span><span style="color: red">ScaleY</span><span style="color: blue">=&quot;1&quot;/&gt;
     &lt;/</span><span style="color: #a31515">TransformGroup</span><span style="color: blue">&gt;
   &lt;/</span><span style="color: #a31515">Grid.RenderTransform</span><span style="color: blue">&gt;
   &lt;</span><span style="color: #a31515">ContentPresenter </span><span style="color: red">Margin</span><span style="color: blue">=&quot;0,20,0,0&quot;/&gt;
&lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;</span></pre>
</p></div>
</blockquote>
<ul>
<li>
<div align="justify">Au même titre dans le VisualState Collapsed, nous avons une storyboard pour assigner la valeur 0 à la propriété ScaleY. </div>
</li>
</ul>
<blockquote>
<p align="justify">Sauf que cette fois ci, nous avons également une seconde storyboard qui va nous permettre de réduire la hauteur de la ligne contenant le ContentPresenter jusqu&#8217;à une hauteur de 0. </p>
</blockquote>
<p align="justify">A la vue de ces deux animations, on est en droit de se demander, pourquoi je n&#8217;ai pas jouer directement sur la hauteur de la row. Les Row qui sont des éléments de RowDefinition ont une propriété Height, mais dans ce cas précis, le type de la propriété est un GridLength. La DoubleAnimation est donc incompatible et le seul le moyen que je vois serait de créer une animation personnalisée juste pour traiter les hauteurs et largeurs de Grid.</p>
<p align="justify">Un peu plus haut dans ce billet, nous avions dit que nous placerions un élément au niveau du header pour masquer / afficher le contenu et que cet élément était un ToggleButton. Un ToggleButton possède plusieurs états dont Checked et Unchecked. Au même titre que ce que nous venons de faire, nous pouvons redéfinir les VisualStates correspondants de manière à pouvoir animer ce ToggleButton. Pour y parvenir, redéfinissons son Template.</p>
<div align="justify">
<pre class="code">  <span style="color: blue">&lt;</span><span style="color: #a31515">ControlTemplate </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;ToggleButton&quot;&gt;
     &lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
       &lt;</span><span style="color: #a31515">Path </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;arrow&quot; </span><span style="color: red">Stroke</span><span style="color: blue">=&quot;#000&quot;
                 </span><span style="color: red">StrokeThickness</span><span style="color: blue">=&quot;2&quot;
                 </span><span style="color: red">Height</span><span style="color: blue">=&quot;Auto&quot;
                 </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Center&quot;
                 </span><span style="color: red">Margin</span><span style="color: blue">=&quot;0,10,30,0&quot;
                 </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Center&quot;
                 </span><span style="color: red">Width</span><span style="color: blue">=&quot;Auto&quot;
                 </span><span style="color: red">RenderTransformOrigin</span><span style="color: blue">=&quot;0.5,0.5&quot;
                 </span><span style="color: red">Data</span><span style="color: blue">=&quot;M 1,1.5 L 4.5,5 L 8,1.5&quot;&gt;
                &lt;</span><span style="color: #a31515">Path.RenderTransform</span><span style="color: blue">&gt;
                  &lt;</span><span style="color: #a31515">TransformGroup</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">ScaleTransform</span><span style="color: blue">/&gt;
                    &lt;</span><span style="color: #a31515">SkewTransform</span><span style="color: blue">/&gt;
                    &lt;</span><span style="color: #a31515">RotateTransform </span><span style="color: red">CenterX</span><span style="color: blue">=&quot;0.5&quot; </span><span style="color: red">CenterY</span><span style="color: blue">=&quot;0.5&quot;
                                </span><span style="color: red">Angle</span><span style="color: blue">=&quot;0&quot;/&gt;
                    &lt;</span><span style="color: #a31515">TranslateTransform</span><span style="color: blue">/&gt;
                   &lt;/</span><span style="color: #a31515">TransformGroup</span><span style="color: blue">&gt;
                  &lt;/</span><span style="color: #a31515">Path.RenderTransform</span><span style="color: blue">&gt;
                 &lt;/</span><span style="color: #a31515">Path</span><span style="color: blue">&gt;
       &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">ControlTemplate</span><span style="color: blue">&gt;
</span></pre>
</div>
<p align="justify">Nous avons un objet Path qui a été créé avec Blend et auquel nous appliquons une transformation de type RotateTransform. Le centre de rotation correspond au centre de l&#8217;objet Path. Visuellement on obtient une petite flèche comme celle-ci.</p>
<p align="justify"><a href="http://blog.experida.fr/wp-content/uploads/2011/02/image.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2011/02/image_thumb.png" width="240" height="77" /></a> Maintenant nous pouvons ajouter, les deux VisualStates:</p>
<ul>
<li>
<div align="justify">Checked</div>
</li>
</ul>
<div align="justify">
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">VisualState </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Checked&quot;&gt;
   &lt;</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
       &lt;</span><span style="color: #a31515">DoubleAnimation </span><span style="color: red">Storyboard.TargetName</span><span style="color: blue">=&quot;arrow&quot;
            </span><span style="color: red">Storyboard.TargetProperty</span><span style="color: blue">=&quot;(UIElement.RenderTransform)
                     .(TransformGroup.Children)[2].(RotateTransform.Angle)&quot;
            </span><span style="color: red">To</span><span style="color: blue">=&quot;0&quot; </span><span style="color: red">Duration</span><span style="color: blue">=&quot;0:0:0.3&quot;/&gt;
   &lt;/</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">VisualState</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<ul>
<li>
<div align="justify">Unchecked</div>
</li>
</ul>
<div align="justify">
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">VisualState </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Unchecked&quot;&gt;
   &lt;</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
       &lt;</span><span style="color: #a31515">DoubleAnimation </span><span style="color: red">Storyboard.TargetName</span><span style="color: blue">=&quot;arrow&quot;
          </span><span style="color: red">Storyboard.TargetProperty</span><span style="color: blue">=&quot;(UIElement.RenderTransform)
           .(TransformGroup.Children)[2].(RotateTransform.Angle)&quot;
          </span><span style="color: red">To</span><span style="color: blue">=&quot;180&quot; </span><span style="color: red">Duration</span><span style="color: blue">=&quot;0:0:0.3&quot;/&gt;
   &lt;/</span><span style="color: #a31515">Storyboard</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">VisualState</span><span style="color: blue">&gt;
</span></pre>
</div>
<p align="justify">Quand le ToggleButton est dans un état Unchecked, nous réalisons une rotation de 180°. L&#8217;état initial étant un angle de 0, nous pourrions ne pas mettre de storyboard dans le VisualState Checked, l&#8217;élément reviendrait tout seul à sa position initiale car deux VisualStates d&#8217;un même VisualStateGroup ne peuvent être appliqués en même temps. Cependant elle est présente afin que cette opération se fasse sur une durée donnée. </p>
<p align="justify">Si nous devions arrêter le développement de notre contrôle à ce stade, il serait totalement exploitable.</p>
<p align="justify">Dans le code joint à ce billet, vous pourrez également trouver quelques propriétés supplémentaires permettant de simplifier sa personnalisation:</p>
<ul>
<li>
<div align="justify">HeaderStyle appliquée à la propriété Style du TextBlock</div>
</li>
<li>
<div align="justify">ToggleButtonStyle appliquée à la propriété Style du ToggleButton</div>
</li>
<li>
<div align="justify">SeparatorStyle appliquée à la propriété Style du Rectangle servant de séparateur entre le header et la contenu.</div>
</li>
<li>
<div align="justify">SeparatorVisibility appliquée à la propriété Visibility du rectangle.</div>
</li>
</ul>
<p align="justify">Dans le generic.xaml, nous nous sommes appuyés sur ces propriétés pour fournir des styles par défaut à notre contrôle.</p>
<p align="justify">Maintenant, vous pouvez soit redéfinir&#160; un / chacun de ces styles, ou bien modifier complètement son template.</p>
<p align="justify">Pour l&#8217;utiliser, ajoutez une référence vers l&#8217;assembly du contrôle, et insérez le code suivant</p>
<div align="justify">
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;LayoutRoot&quot; </span><span style="color: red">Background</span><span style="color: blue">=&quot;White&quot;&gt;
        &lt;</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander
            </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Top&quot;
            </span><span style="color: red">HeaderText</span><span style="color: blue">=&quot;Header&quot; </span><span style="color: red">Background</span><span style="color: blue">=&quot;LightSkyBlue&quot; &gt;
                &lt;</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander.Content</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;Content&quot; /&gt;
                        &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Width</span><span style="color: blue">=&quot;150&quot; </span><span style="color: red">Height</span><span style="color: blue">=&quot;150&quot; </span><span style="color: red">Fill</span><span style="color: blue">=&quot;Black&quot;/&gt;
                    &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander.Content</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander
            </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Top&quot;
            </span><span style="color: red">HeaderText</span><span style="color: blue">=&quot;Header&quot; </span><span style="color: red">Background</span><span style="color: blue">=&quot;LightSkyBlue&quot; &gt;
                &lt;</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander.Content</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;Content&quot; /&gt;
                        &lt;</span><span style="color: #a31515">Rectangle </span><span style="color: red">Width</span><span style="color: blue">=&quot;150&quot; </span><span style="color: red">Height</span><span style="color: blue">=&quot;150&quot; </span><span style="color: red">Fill</span><span style="color: blue">=&quot;Black&quot;/&gt;
                    &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander.Content</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">local</span><span style="color: blue">:</span><span style="color: #a31515">Expander</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify"><u>Démo</u></p>
<p align="justify">
<div align="justify"><object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="450" height="600"><param name="source" value="http://blog.experida.fr/wp-content/uploads/2011/02/Expander1.zip" /><param name="onError" value="onSilverlightError" /><param name="background" value="white" /><param name="minRuntimeVersion" value="4.0.50826.0" /><param name="autoUpgrade" value="true" /><a href="http://go.microsoft.com/fwlink/?LinkID=149156&amp;v=4.0.50826.0" style="text-decoration:none"><br />
 			  <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none" /><br />
		  </a><br />
	    </object><iframe style="border-right-width: 0px; width: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px; visibility: hidden; border-left-width: 0px" id="_sl_historyFrame"></iframe></div>
<p align="justify"><a href="http://blog.experida.fr/wp-content/uploads/2011/02/Expander.zip">Télécharger le code</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/02/11/silverlight-developpement-dun-expander/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight &#8211; G&#233;rer l&#8217;&#233;tat Activ&#233; / d&#233;sactiv&#233; d&#8217;un bouton avec une ICommand</title>
		<link>http://blog.experida.fr/2011/01/19/silverlight-gerer-letat-active-desactive-dun-bouton-avec-une-icommand/</link>
		<comments>http://blog.experida.fr/2011/01/19/silverlight-gerer-letat-active-desactive-dun-bouton-avec-une-icommand/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 22:47:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[ICommand]]></category>
		<category><![CDATA[RaiseCanExecuteChanged]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/01/19/silverlight-gerer-letat-active-desactive-dun-bouton-avec-une-icommand/</guid>
		<description><![CDATA[Dans le développement d&#8217;une application Silverlight ou WPF, on a l&#8217;habitude d&#8217;utiliser les ICommand pour communiquer de manière découplée entre une View (V) et un ViewModel (VM). Regardons d&#8217;un peu plus près de quelles propriétés / méthodes est constituée cette interface. public interface ICommand { event EventHandler CanExecuteChanged; bool CanExecute(object parameter); void Execute(object parameter); } [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Dans le développement d&#8217;une application Silverlight ou WPF, on a l&#8217;habitude d&#8217;utiliser les ICommand pour communiquer de manière découplée entre une View (V) et un ViewModel (VM).</p>
<p align="justify">Regardons d&#8217;un peu plus près de quelles propriétés / méthodes est constituée cette interface.</p>
<p> <span id="more-275"></span>
<div align="justify">
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">ICommand
</span>{
<span style="color: blue">   event </span><span style="color: #2b91af">EventHandler </span>CanExecuteChanged;
<span style="color: blue">   bool </span>CanExecute(<span style="color: blue">object </span>parameter);
<span style="color: blue">   void </span>Execute(<span style="color: blue">object </span>parameter);
}</pre>
</div>
<p align="justify">
<ul>
<li>
<div align="justify">CanExecute permet de dire si la commande peut être exécutée.</div>
</li>
<li>
<div align="justify">Execute comme son nom l&#8217;indique exécute la commande</div>
</li>
<li>
<div align="justify">CanExecuteChanged est un event que l&#8217;on va utiliser pour déclencher l&#8217;appel de la méthode CanExecute et changer notamment l&#8217;état de la source liée à la commande. Il peut s&#8217;agir par exemple d&#8217;un bouton et de son état IsEnabled.</div>
</li>
</ul>
<p align="justify">Avant d&#8217;allez plus loin, créons un petit projet pour continuer ce billet. </p>
<p align="justify">Ouvrez votre visual studio et créez une application silverlight v4. Puis ajoutez-y une classe User avec deux propriétés LastName,FirstName et implémentez l&#8217;interface INotifyPropertyChanged pour notifier tout changement de valeur d&#8217;une des propriétés.</p>
<div align="justify">
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">User </span>: <span style="color: #2b91af">EntityBase
   </span>{
       <span style="color: blue">private string </span>lastName;
       <span style="color: blue">public string </span>LastName
       {
           <span style="color: blue">get </span>{ <span style="color: blue">return </span>lastName; }
           <span style="color: blue">set
           </span>{
               <span style="color: blue">if </span>(<span style="color: blue">value </span>!= lastName)
               {
                   lastName = <span style="color: blue">value</span>;
                   RaisePropertyChanged(() =&gt; LastName);
               }
           }
       }

       <span style="color: blue">private string </span>firstName;
       <span style="color: blue">public string </span>FirstName
       {
           <span style="color: blue">get </span>{ <span style="color: blue">return </span>firstName; }
           <span style="color: blue">set
           </span>{
               <span style="color: blue">if </span>(<span style="color: blue">value </span>!= firstName)
               {
                   firstName = <span style="color: blue">value</span>;
                   RaisePropertyChanged(() =&gt; FirstName);
               }
           }
       }

   }</pre>
</div>
<p align="justify">Maintenant, nous allons créer une classe MainViewModel et la faire hériter de ViewModelBase. ViewModelBase est une classe que j&#8217;ai ajouté au projet et que j&#8217;utilise dans tous mes projets Silverlight et WPF notamment pour fournir INotifyPropertyChanged.</p>
<p align="justify">On va y ajouter une propriété User sur laquelle notre UI va se binder, et une propriété SaveCommand de type ICommand sur laquelle va se binder un bouton pour lancer la validation de l&#8217;utilisateur. </p>
<p align="justify">A cet instant notre classe MainViewModel est constituée du code suivant:</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">MainViewModel </span>: <span style="color: #2b91af">ViewModelBase
    </span>{
        <span style="color: blue">private </span><span style="color: #2b91af">ICommand </span>saveCommand;

        <span style="color: blue">public </span>MainViewModel()
        {
            User = <span style="color: blue">new </span><span style="color: #2b91af">User</span>();
        }

        <span style="color: blue">private </span><span style="color: #2b91af">User </span>user;
        <span style="color: blue">public </span><span style="color: #2b91af">User </span>User
        {
            <span style="color: blue">get </span>{ <span style="color: blue">return </span>user; }
            <span style="color: blue">set
            </span>{
                <span style="color: blue">if </span>(<span style="color: blue">value </span>!= user)
                {
                    user = <span style="color: blue">value</span>;
                    RaisePropertyChanged(() =&gt; User);
                }
            }
        }

        <span style="color: blue">public </span><span style="color: #2b91af">ICommand </span>SaveCommand
        {
            <span style="color: blue">get
            </span>{
                <span style="color: blue">if </span>(saveCommand == <span style="color: blue">null</span>)
                    saveCommand
                        = <span style="color: blue">new </span><span style="color: #2b91af">RelayCommand</span>&lt;<span style="color: blue">string</span>&gt;(param =&gt; SaveUser(),
                            param =&gt; CanSaveUser());
                <span style="color: blue">return </span>saveCommand;
            }
        }

        <span style="color: blue">private bool </span>CanSaveUser()
        {
            <span style="color: blue">return </span>User != <span style="color: blue">null </span>&amp;&amp; !<span style="color: blue">string</span>.IsNullOrEmpty(User.FirstName)
                &amp;&amp; !<span style="color: blue">string</span>.IsNullOrEmpty(User.LastName);
        }

        <span style="color: blue">private void </span>SaveUser()
        {
            <span style="color: green">//TODO: ajouter le code pour sauvergarder l'utilisateur
        </span>}
    }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Il nous reste plus qu&#8217;à créer l&#8217;UI en xaml, avec deux TextBox, un bouton et le Binding nécessaire pour associer ces contrôles avec les propriétés de User et la Commande SaveCommand.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Grid </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;LayoutRoot&quot; </span><span style="color: red">Background</span><span style="color: blue">=&quot;White&quot;&gt;
        &lt;</span><span style="color: #a31515">Grid.RowDefinitions</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">Height</span><span style="color: blue">=&quot;25&quot; /&gt;
            &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">Height</span><span style="color: blue">=&quot;25&quot; /&gt;
            &lt;</span><span style="color: #a31515">RowDefinition </span><span style="color: red">Height</span><span style="color: blue">=&quot;25&quot; /&gt;
        &lt;/</span><span style="color: #a31515">Grid.RowDefinitions</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">Grid.ColumnDefinitions</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ColumnDefinition</span><span style="color: blue">/&gt;
            &lt;</span><span style="color: #a31515">ColumnDefinition</span><span style="color: blue">/&gt;
        &lt;/</span><span style="color: #a31515">Grid.ColumnDefinitions</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;LastName: &quot; </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Right&quot;/&gt;
        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;1&quot;
                   </span><span style="color: red">Text</span><span style="color: blue">=&quot;FirstName: &quot;
                   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Right&quot; /&gt;
        &lt;</span><span style="color: #a31515">TextBox </span><span style="color: red">Grid.Column</span><span style="color: blue">=&quot;1&quot;
                 </span><span style="color: red">Width</span><span style="color: blue">=&quot;150&quot;
                 </span><span style="color: red">Text</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">Binding </span><span style="color: red">User</span><span style="color: blue">.LastName,</span><span style="color: red">Mode</span><span style="color: blue">=TwoWay}&quot;
                 </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Left&quot; /&gt;
        &lt;</span><span style="color: #a31515">TextBox </span><span style="color: red">Grid.Column</span><span style="color: blue">=&quot;1&quot;
                 </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;1&quot;
                 </span><span style="color: red">Width</span><span style="color: blue">=&quot;150&quot;
                 </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Left&quot;
                 </span><span style="color: red">Text</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">Binding </span><span style="color: red">User</span><span style="color: blue">.FirstName,</span><span style="color: red">Mode</span><span style="color: blue">=TwoWay}&quot; /&gt;
        &lt;</span><span style="color: #a31515">Button </span><span style="color: red">Content</span><span style="color: blue">=&quot;Validate&quot;
                </span><span style="color: red">Command</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">Binding </span><span style="color: red">SaveCommand</span><span style="color: blue">}&quot;
                </span><span style="color: red">Grid.Row</span><span style="color: blue">=&quot;2&quot;
                </span><span style="color: red">Grid.Column</span><span style="color: blue">=&quot;1&quot; /&gt;
    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
</span></pre>
<p>Et à associer View et ViewModel dans le code behind.</p>
<pre class="code"><span style="color: blue">this</span>.DataContext = <span style="color: blue">new </span><span style="color: #2b91af">MainViewModel</span>();</pre>
<p>Lancez l&#8217;application. Normalement vous devriez avoir à l&#8217;écran vos deux textbox et le bouton validate. Mais vous constaterez que le bouton est désactivé. </p>
<p>En effet, si vous vous souvenez, au début du billet nous avons vu les membres de l&#8217;interface ICommand. Dans ce billet nous avons utilisé une implémentation de ICommand nommée&#160; RelayCommand dont voici le code:</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">RelayCommand</span>&lt;T&gt; : <span style="color: #2b91af">ICommand
  </span>{
      <span style="color: blue">readonly </span><span style="color: #2b91af">Action</span>&lt;T&gt; _execute = <span style="color: blue">null</span>;
      <span style="color: blue">readonly </span><span style="color: #2b91af">Predicate</span>&lt;T&gt; _canExecute = <span style="color: blue">null</span>;

      <span style="color: blue">public </span>RelayCommand(<span style="color: #2b91af">Action</span>&lt;T&gt; execute)
          : <span style="color: blue">this</span>(execute, <span style="color: blue">null</span>)
      {
      }

      <span style="color: blue">public </span>RelayCommand(<span style="color: #2b91af">Action</span>&lt;T&gt; execute,
          <span style="color: #2b91af">Predicate</span>&lt;T&gt; canExecute)
      {
          <span style="color: blue">if </span>(execute == <span style="color: blue">null</span>)
              <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;execute&quot;</span>);

          _execute = execute;
          _canExecute = canExecute;
      }

      <span style="color: blue">public bool </span>CanExecute(<span style="color: blue">object </span>parameter)
      {
          <span style="color: blue">return </span>_canExecute == <span style="color: blue">null </span>? <span style="color: blue">true </span>:
              _canExecute((T)parameter);
      }

      <span style="color: blue">public event </span><span style="color: #2b91af">EventHandler </span>CanExecuteChanged;

       <span style="color: blue">public void </span>Execute(<span style="color: blue">object </span>parameter)
      {
          _execute((T)parameter);
      }

  }</pre>
<p align="justify">Lorsque la target, ici le bouton appelle la méthode CanExecute de l&#8217;interface ICommand, le delegate _canExecute est également appelé. Ce delegate pointe tout simplement vers la méthode que nous avons ajouté dans le ViewModel: CanSaveUser et retourne une valeur de type boolean. Si la valeur est égale à false, le bouton est alors désactivé.</p>
<p align="justify">Si vous tentez de modifier le texte des textbox, l&#8217;objet User est bien modifié, cependant le bouton validate reste toujours désactivé, car la méthode CanSave n&#8217;est pas réévaluée.</p>
<p align="justify">Contrairement à WPF, où il existe un objet CommandManager chargé de relancer la méthode CanExecute lorsqu&#8217;un changement au niveau d&#8217;une propriété de l&#8217;UI est détecté, nous devons nous même appeler l&#8217;event CanExecuteChanged de ICommand avec Silverlight.</p>
<p align="justify">Ce que nous souhaitons dans notre cas, c&#8217;est que l&#8217;event soit déclenché à chaque fois que FistName ou LastName est modifiée. Pour cela nous allons étendre RelayCommand en implémentant une nouvelle interface que l&#8217;on nommera ICommandExntension avec une méthode RaiseCanExecuteChanged.</p>
<pre class="code"><span style="color: blue">public void </span>RaiseCanExecuteChanged()
       {
           <span style="color: #2b91af">EventHandler </span>handler = <span style="color: blue">this</span>.CanExecuteChanged;
           <span style="color: blue">if </span>(handler != <span style="color: blue">null</span>)
               handler(<span style="color: blue">this</span>, <span style="color: #2b91af">EventArgs</span>.Empty);
       }</pre>
<p>User implémente INotifyPropertyChanged. Nous allons donc nous abonner à cet event dans le ViewModel, puis dans le handler correspondant, nous allons utiliser SaveCommand en tant que ICommandExtension et appeler la méthode RaiseCanExecuteChanged. </p>
<p>Et voilà, avec ce code, la méthode CanSave sera de nouveau appelée et le bouton sera automatiquement réactivé dès que les conditions nécessaires seront validées.</p>
<pre class="code"><span style="color: blue">public </span>MainViewModel()
       {
           User = <span style="color: blue">new </span><span style="color: #2b91af">User</span>();
           User.PropertyChanged +=
               <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedEventHandler</span>(User_PropertyChanged);
       }

       <span style="color: blue">void </span>User_PropertyChanged(<span style="color: blue">object </span>sender,
           System.ComponentModel.<span style="color: #2b91af">PropertyChangedEventArgs </span>e)
       {
           ((<span style="color: #2b91af">ICommandExtension</span>)SaveCommand).RaiseCanExecuteChanged();
       }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Code du billet: <a href="http://blog.experida.fr/wp-content/uploads/2011/01/RaiseCanExecuteChanged.zip">Télécharger</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/01/19/silverlight-gerer-letat-active-desactive-dun-bouton-avec-une-icommand/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight &#8211; Modifier les styles au runtime</title>
		<link>http://blog.experida.fr/2011/01/13/silverlight-modifier-les-styles-au-runtime/</link>
		<comments>http://blog.experida.fr/2011/01/13/silverlight-modifier-les-styles-au-runtime/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 22:59:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[MergedDictionaries]]></category>
		<category><![CDATA[Runtime]]></category>
		<category><![CDATA[StaticResource]]></category>
		<category><![CDATA[Style]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/01/13/silverlight-modifier-les-styles-au-runtime/</guid>
		<description><![CDATA[Lors d&#8217;une mission récente, un des pré-requis graphique était d&#8217;avoir des couleurs différentes au niveau de la&#160; MainPage et des pages de la NavigationFrame en fonction du menu sélectionné. Au travers de ce billet, nous verrons une solution qu&#8217;il est possible d&#8217;implémenter pour modifier les styles des différents contrôles au Runtime. Les styles peuvent être [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Lors d&#8217;une mission récente, un des pré-requis graphique était d&#8217;avoir des couleurs différentes au niveau de la&#160; MainPage et des pages de la NavigationFrame en fonction du menu sélectionné.</p>
<p align="justify">Au travers de ce billet, nous verrons une solution qu&#8217;il est possible d&#8217;implémenter pour modifier les styles des différents contrôles au Runtime.</p>
<p> <span id="more-273"></span>
<p align="justify">Les styles peuvent être utilisés de deux manières différentes:</p>
<ul>
<li>
<div align="justify">Les styles que l&#8217;on appelle styles implicites. Lors de la déclaration du style, vous ne définissez pas de x:Key mais seulement un TargetType. Tous les contrôles de ce type utiliseront alors ce style</div>
</li>
<li>
<div align="justify">Les styles que l&#8217;on peut nommer styles explicites. Contrairement au précédent, la déclaration du style contient un x:Key et un TargetType. Afin qu&#8217;un contrôle puisse utiliser ce type de style, il doit spécifier le style via la propriété Style du contrôle à l&#8217;aide de StaticResource.</div>
</li>
</ul>
<p align="justify">Seulement contrairement à WPF, où il existe les DynamicResources, Silverlight ne propose que StaticResource.&#160; Vous allez me dire, oui mais où se trouve la différence entre ces deux méthodes.</p>
<p align="justify">Globalement la grosse différence réside dans le fait que la résolution d&#8217;une StaticResource est réalisée lorsque le xaml de la page est parcouru. Cette opération arrive une fois et vous ne pouvez plus modifier aucune ressource après ça. </p>
<p align="justify">A contrario avec les DynamicResources, la ressource est évaluée au Runtime. Le gros avantage, c&#8217;est que vous allez notamment pouvoir mettre à jour la target / contrôle, dès qu&#8217;un changement est effectué dans un ResourceDictionary. Ceci est très pratique pour appliquer des thèmes à son application.</p>
<p align="justify">Heureusement depuis Silverlight 3 des améliorations ont été faites sur la gestion des styles et maintenant nous pouvons mettre à un jour le style d&#8217;un contrôle en lui assignant un nouveau style. A noté également la gestion des MergedDictionaries qui permet de composer les styles à partir de plusieurs sources.</p>
<p align="justify">Pour mettre en avant ce que nous venons de voir, je vous propose un exemple très simple, dans lequel nous allons simplement modifier la couleur d&#8217;un Border et la disposition des contrôles. Le xaml sera composé des éléments suivants:</p>
<div align="justify">
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">UserControl </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">=&quot;SilverlightDynamicMergeDictionaries.MainPage&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">d</span><span style="color: blue">=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">mc</span><span style="color: blue">=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    </span><span style="color: red">mc</span><span style="color: blue">:</span><span style="color: red">Ignorable</span><span style="color: blue">=&quot;d&quot;
    </span><span style="color: red">d</span><span style="color: blue">:</span><span style="color: red">DesignHeight</span><span style="color: blue">=&quot;300&quot; </span><span style="color: red">d</span><span style="color: blue">:</span><span style="color: red">DesignWidth</span><span style="color: blue">=&quot;400&quot;&gt;

    &lt;</span><span style="color: #a31515">Grid </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;LayoutRoot&quot; </span><span style="color: red">Background</span><span style="color: blue">=&quot;White&quot;&gt;
        &lt;</span><span style="color: #a31515">StackPanel  </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Center&quot;&gt;
            &lt;</span><span style="color: #a31515">Border </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;MyBorder&quot; </span><span style="color: red">Style</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">StaticResource </span><span style="color: red">Test</span><span style="color: blue">}&quot;
                    </span><span style="color: red">Width</span><span style="color: blue">=&quot;100&quot;
                    </span><span style="color: red">Height</span><span style="color: blue">=&quot;100&quot;&gt;
            &lt;/</span><span style="color: #a31515">Border</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">Button </span><span style="color: red">Click</span><span style="color: blue">=&quot;Button_Click&quot;
                    </span><span style="color: red">Tag</span><span style="color: blue">=&quot;Red&quot; </span><span style="color: red">Width</span><span style="color: blue">=&quot;150&quot;
                    </span><span style="color: red">Height</span><span style="color: blue">=&quot;25&quot;
                    </span><span style="color: red">Content</span><span style="color: blue">=&quot;Theme Red&quot;/&gt;
            &lt;</span><span style="color: #a31515">Button </span><span style="color: red">Click</span><span style="color: blue">=&quot;Button_Click&quot;
                    </span><span style="color: red">Tag</span><span style="color: blue">=&quot;Blue&quot; </span><span style="color: red">Width</span><span style="color: blue">=&quot;150&quot;
                    </span><span style="color: red">Height</span><span style="color: blue">=&quot;25&quot;
                    </span><span style="color: red">Content</span><span style="color: blue">=&quot;Theme Blue&quot;/&gt;
        &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">UserControl</span><span style="color: blue">&gt;

</span></pre>
</div>
<p align="justify">Nous souhaitons définir le style du StackPanel avec un style implicite et le style de l&#8217;élément Border avec un style explicite. Comme vous le remarquerez, nous associons le style avec le x:key Test à l&#8217;élément Border.</p>
<p align="justify">Ces deux styles, nous allons les définir dans un dictionnaire de ressources. Comme dit plus haut, nous souhaitons pouvoir modifier ces styles au runtime, pour cela nous allons ajouter non pas un, mais deux dictionnaires de ressources: blue.xaml et red.xaml</p>
<p align="justify">Dans le fichier xaml, j&#8217;ai également ajouté deux boutons, pour switcher entre les styles des deux dictionnaires de ressources que l&#8217;on peut considérer comme des thèmes.</p>
<p align="justify">Partons du principe que le thème par défaut est blue.xaml. Pour l&#8217;utiliser nous devons l&#8217;ajouter aux ressources de l&#8217;application, si l&#8217;on souhaite rendre disponible ces styles à l&#8217;ensemble des contrôles, quelque soit la page, le contrôle&#8230;:</p>
<p align="justify"><u>App.xaml:</u></p>
<div align="justify">
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">Application.Resources</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ResourceDictionary
   </span><span style="color: red">Source</span><span style="color: blue">=&quot;/SilverlightDynamicMergeDictionaries;component/blue.xaml&quot;/&gt;
            &lt;/</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Application.Resources</span><span style="color: blue">&gt;
</span></pre>
</div>
<ul>
<p align="justify">&#160;</p>
<p>  <a href="http://11011.net/software/vspaste"></a></ul>
<p align="justify">Une fois cette première étape faite, ajoutez un handler commun pour les deux boutons. Dans cet exemple, le thème à charger sera déterminé via le Tag que nous avons ajouté à chacun des boutons.</p>
<p align="justify">Comme nous allons avoir besoin d&#8217;ici peu des styles, ajoutons deux variables de type string contenant le chemin vers les ResourcesDictionary.</p>
<div align="justify">
<pre class="code"><span style="color: blue">private const string </span>blueSource
        = <span style="color: #a31515">&quot;/SilverlightDynamicMergeDictionaries;component/blue.xaml&quot;</span>;
<span style="color: blue">private const string </span>redSource
        = <span style="color: #a31515">&quot;/SilverlightDynamicMergeDictionaries;component/red.xaml&quot;</span>;</pre>
</div>
<p align="justify">La nomenclature de nommage est la suivante: /NameSpace;component/Path.xaml</p>
<p align="justify">Maintenant dans le handler, commencez par faire un cast du sender en Button de manière à pouvoir récupérer la valeur correspondant au thème à charger.</p>
<p align="justify">Puis créez un nouveau ResourceDictionary en assignant à sa propriété Source, une Uri qui prend en paramètre soit blueSource, soit redSource. Le ResourceDictionary est créé, il ne nous reste plus qu&#8217;à l&#8217;ajouter au MergedDictionaries de App.Resources.</p>
<div align="justify">
<pre class="code"><span style="color: #2b91af">Button </span>btn = sender <span style="color: blue">as </span><span style="color: #2b91af">Button</span>;
           <span style="color: blue">if </span>(btn != <span style="color: blue">null</span>)
           {
               <span style="color: #2b91af">ResourceDictionary </span>resources =
                   <span style="color: #2b91af">App</span>.Current.Resources <span style="color: blue">as </span><span style="color: #2b91af">ResourceDictionary</span>;

               <span style="color: #2b91af">ResourceDictionary </span>rd = <span style="color: blue">new </span><span style="color: #2b91af">ResourceDictionary</span>();
               <span style="color: blue">if </span>(btn.Tag.Equals(<span style="color: #a31515">&quot;Blue&quot;</span>))
                   rd.Source = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(blueSource, <span style="color: #2b91af">UriKind</span>.Relative);
               <span style="color: blue">else
                   </span>rd.Source = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(redSource, <span style="color: #2b91af">UriKind</span>.Relative);

               resources.MergedDictionaries.Add(rd);</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">A ce stade nous avons ajouté les nouveaux styles. Il nous reste une dernière étape, à savoir, faire en sorte que l&#8217;UI soit mise à jour.</p>
<p align="justify">Pour cela quelques explications supplémentaires sont nécessaires.</p>
<p align="justify">Si vous avez fait attention, entre le dictionnaire ajouté dans App.xaml et celui que nous venons d&#8217;ajouter après le click du bouton, MergedDictionaries contient deux dictionnaires avec exactement les mêmes styles.</p>
<p align="justify">D&#8217;après la msdn, voici ce qui se passe si j&#8217;essaie de récupérer un style dans ce cas de figure.</p>
<blockquote>
<p align="justify">Merged Dictionary Behavior</p>
<div align="justify">
<hr /></div>
<p align="justify"><a></a></p>
<p align="justify">Resources in a merged dictionary occupy a location in the resource lookup scope that is just after the scope of the main resource dictionary they are merged into. Although a resource key must be unique within any individual dictionary, a key can exist multiple times in a set of merged dictionaries. In this case, the resource that is returned will come from the last dictionary found sequentially in the MergedDictionaties collection. If the MergedDictionaties collection was defined in XAML, then the order of the merged dictionaries in the collection is the order of the elements as provided in the markup. If a key is defined in the primary dictionary and also in a dictionary that was merged, then the resource that is returned will come from the primary dictionary. These scoping rules apply equally for both static resource references and dynamic resource references.</p>
</blockquote>
<p align="justify">Dans notre cas, seule la partie MergedDictionaries nous intéresse. Le Style que nous allons récupérer correspond donc bien au style présent dans le dernier Dictionnaire de ressources ajouté.</p>
<p align="justify">Pour assigner les nouveaux styles, nous allons parcourir l&#8217;arborescence XAML et pour chacun des contrôles regarder si un style est présent dans les ressources de l&#8217;application.</p>
<p align="justify">Pour parcourir le XAML voici une méthode d&#8217;extension.</p>
<div align="justify">
<pre class="code"><span style="color: blue">public static </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">DependencyObject</span>&gt;
           Descendents(<span style="color: blue">this </span><span style="color: #2b91af">DependencyObject </span>root)
       {
           <span style="color: blue">int </span>count = <span style="color: #2b91af">VisualTreeHelper</span>.GetChildrenCount(root);
           <span style="color: blue">for </span>(<span style="color: blue">int </span>i = 0; i &lt; count; i++)
           {
               <span style="color: blue">var </span>child = <span style="color: #2b91af">VisualTreeHelper</span>.GetChild(root, i);
               <span style="color: blue">yield return </span>child;
               <span style="color: blue">foreach </span>(<span style="color: blue">var </span>descendent <span style="color: blue">in </span>Descendents(child))
                   <span style="color: blue">yield return </span>descendent;
           }
       }</pre>
</div>
<p align="justify">Pour l&#8217;utiliser, il nous suffit de choisir un DependencyObject correspondant à la partie de l&#8217;UI que nous souhaitons rafraichir et de parcourir les éléments dans une boucle foreach en appelant la méthode récursive Descendents.</p>
<div align="justify">
<pre class="code"><span style="color: blue">this</span>.Descendents().ToList().ForEach(c =&gt; ApplyNewStyle(c));</pre>
</div>
<p align="justify">Dans l&#8217;expression lambda ci-dessus, vous pouvez voir que nous avons également ajouté une méthode ApplyNewStyle avec le contrôle sur lequel on doit l&#8217;appliquer. C&#8217;est dans cette méthode que nous allons parcourir les dictionnaires, pour trouver l&#8217;identifiant correspondant au style et ainsi le récupérer pour l&#8217;assigner.</p>
<div align="justify">
<pre class="code"><span style="color: blue">private void </span>ApplyNewStyle(<span style="color: #2b91af">DependencyObject </span>ctrl)
{
 <span style="color: #2b91af">FrameworkElement </span>element = ctrl <span style="color: blue">as </span><span style="color: #2b91af">FrameworkElement</span>;
<span style="color: blue"> if </span>(element != <span style="color: blue">null</span>)
 {
   <span style="color: blue">foreach </span>(<span style="color: #2b91af">ResourceDictionary </span>dictionary
           <span style="color: blue">in </span><span style="color: #2b91af">App</span>.Current.Resources.MergedDictionaries)
   {
      <span style="color: blue">foreach </span>(<span style="color: blue">object </span>key <span style="color: blue">in </span>dictionary.Keys)
      {
       <span style="color: blue">if </span>((element.Style != <span style="color: blue">null </span>&amp;&amp; element.Style == dictionary[key]) ||
              (key.ToString() == element.GetType().FullName))
            element.Style = <span style="color: #2b91af">App</span>.Current.Resources[key] <span style="color: blue">as </span><span style="color: #2b91af">Style</span>;
      }
   }
 }
}</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Nous pourrions ne parcourir que le premier dictionnaire car nous savons que dans cet exemple, les deux seuls dictionnaires présents dans MergedDictionaries sont les dictionnaires correspondant à nos styles et que le premier contient les styles de départ. Cependant, dans une application réelle, rien ne vous empêche d&#8217;en avoir d&#8217;autres.</p>
<p align="justify">Pour joindre le bon style au bon contrôle, deux cas se présentent à nous. </p>
<ul>
<li>
<div align="justify">Le cas du StackPanel, où nous avions pas ajouté de x:key (style implicite). En réalité une clé est générée. Plus précisément il s&#8217;agit du type du contrôle que l&#8217;on a mis dans TargetType. Nous devons donc comparer avec le type de notre contrôle. </div>
</li>
<li>
<div align="justify">La cas du Border sur lequel nous avons ajouté explicitement un style. Ici il nous suffit donc de comparer le style du contrôle avec le style du dictionnaire possédant la clé courante. </div>
</li>
</ul>
<p align="justify">Dernier point. Comme maintenant les styles appliqués sont ceux du dernier dictionnaire ajouté, nous pouvons supprimer le dictionnaire qui se trouve ici à l&#8217;index 0.</p>
<p align="justify">Le même processus sera effectué à chaque fois que l&#8217;on clique sur un des deux boutons.</p>
<p align="justify">Comme d&#8217;habitude, voici les <a href="http://blog.experida.fr/wp-content/uploads/2011/01/SilverlightDynamicMergeDictionaries.zip" target="_blank">sources</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/01/13/silverlight-modifier-les-styles-au-runtime/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4 &#8211; Validation de donn&#233;es avec INotifyDataErrorInfo</title>
		<link>http://blog.experida.fr/2011/01/04/silverlight-4-validation-de-donnees-avec-inotifydataerrorinfo/</link>
		<comments>http://blog.experida.fr/2011/01/04/silverlight-4-validation-de-donnees-avec-inotifydataerrorinfo/#comments</comments>
		<pubDate>Mon, 03 Jan 2011 23:23:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Asynchrone]]></category>
		<category><![CDATA[INotifyDataErrorInfo]]></category>
		<category><![CDATA[Silverlight 4]]></category>
		<category><![CDATA[ValidatesOnNotifyDataErrors]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2011/01/04/silverlight-4-validation-de-donnees-avec-inotifydataerrorinfo/</guid>
		<description><![CDATA[Lors du développement d&#8217;une application, le développeur doit s&#8217;assurer que l&#8217;utilisateur ne pourra pas entrer de données non valides. Avec Silverlight 4, il existe plusieurs méthodes pour procéder à la validation des données. Via des attributs que l&#8217;on peut trouver dans System.ComponentModel.DataAnnotations L&#8217;interface IDataErrorInfo L&#8217;interface INotifyDataErrorInfo Dans ce billet je vous propose de voir plus [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Lors du développement d&#8217;une application, le développeur doit s&#8217;assurer que l&#8217;utilisateur ne pourra pas entrer de données non valides.</p>
<p align="justify">Avec Silverlight 4, il existe plusieurs méthodes pour procéder à la validation des données.</p>
<ul>
<li>
<div align="justify">Via des attributs que l&#8217;on peut trouver dans System.ComponentModel.DataAnnotations</div>
</li>
<li>
<div align="justify">L&#8217;interface IDataErrorInfo</div>
</li>
<li>
<div align="justify">L&#8217;interface INotifyDataErrorInfo</div>
</li>
</ul>
<p align="justify">Dans ce billet je vous propose de voir plus en détail comment utiliser INotifyDataErrorInfo. </p>
<p> <span id="more-271"></span>
<p align="justify">Par rapport à IDataErrorInfo, cette interface permet de mettre en place une validation asynchrone. Autre avantage, nous pouvons associer plusieurs erreurs à une propriété sans avoir besoin de concaténer les erreurs. </p>
<p align="justify">En effet avec IDataErrorInfo, la récupération de l&#8217;erreur se fait via une propriété indexée prenant en argument le nom de la propriété à valider et retournant juste une string correspondant à l&#8217;erreur. </p>
<p align="justify">Par exemple prenons une classe User dont une des propriétés est Name. User implémente l&#8217;interface IDataErrorInfo. Le Name ne doit pas être null ou une chaine vide.</p>
<pre class="code"><span style="color: blue">public string this</span>[<span style="color: blue">string </span>propertyName]
       {
           <span style="color: blue">get
           </span>{
               <span style="color: blue">switch </span>(propertyName)
               {
                   <span style="color: blue">case </span><span style="color: #a31515">&quot;Name&quot;</span>:
                       <span style="color: blue">if </span>(<span style="color: blue">string</span>.IsNullOrEmpty(Name))
                           <span style="color: blue">return </span><span style="color: #a31515">&quot;Name cannot be null or empty&quot;</span>;
                       <span style="color: blue">break</span>;
               }

               <span style="color: blue">return null</span>;
           }
       }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Maintenant dans le cas où le Name ne serait pas null, on pourrait par exemple vérifier que Name contient au moins 6 caractères&#160; et que ce Name n&#8217;est pas déjà utilisé. Si les deux conditions ne sont pas respectées on veut alors retourner à l&#8217;utilisateur les deux erreurs. Le seul moyen que nous avons ici est de faire la concaténation des deux erreurs et de la retourner à l&#8217;utilisateur.</p>
<p align="justify">Venons en justement à la vérification de l&#8217;unicité du Name. Cette vérification ne peut être effectuée que du côté serveur. Comme toute opération serveur celle-ci peut prendre plus ou moins de temps avant de retourner une réponse au client. </p>
<p align="justify">Avec Silverlight tous les appels au serveur sont asynchrones et une fois le résultat récupéré il faut trouver un moyen de notifier l&#8217;utilisateur pour lui indiquer si il y a une erreur et plus précisément ici, si le Name est déjà utilisé par un autre User. C&#8217;est là qu&#8217;intervient l&#8217;interface INotifyDataErrorInfo.</p>
<p align="justify"><u>Détaillons le contenu de cette interface:</u></p>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">INotifyDataErrorInfo
</span>{
   <span style="color: green"> </span><span style="color: blue">bool </span>HasErrors { <span style="color: blue">get</span>; }<span style="color: green">
    </span><span style="color: blue">event </span><span style="color: #2b91af">EventHandler</span>&lt;<span style="color: #2b91af">DataErrorsChangedEventArgs</span>&gt; ErrorsChanged;<span style="color: green">
    </span><span style="color: #2b91af">IEnumerable </span>GetErrors(<span style="color: blue">string </span>propertyName);
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<ul>
<li>HasErrors: permet de savoir si l&#8217;entité contient des erreurs </li>
<li>ErrorsChanged: est levé quand une erreur est ajoutée, supprimée ou modifiée </li>
<li>GetErrors: permet de récupérer la collection des erreurs liées à une propriété. </li>
</ul>
<p>Voyons maintenant comment l&#8217;implémenter avec notre classe User.</p>
<p>Commençons par créer une classe de base qui implémente l&#8217;interface INotifyDataErrorInfo. Vous pourrez ainsi appliquer ce comportement avec de nouvelles entités.</p>
<p>Nous allons appeler cette classe ModelBase.</p>
<p><u>Contenu de ModelBase:</u></p>
<div align="justify">
<pre class="code"><span style="color: blue">private readonly </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;&gt; dataErrors =
    <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;&gt;();

<span style="color: blue">protected
  void </span>AddError&lt;T&gt;(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;T&gt;&gt; propertyExpression, <span style="color: blue">string </span>errorText)
{
    <span style="color: blue">if </span>(propertyExpression == <span style="color: blue">null</span>)
        <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;propertyExpression&quot;</span>);

    <span style="color: blue">string </span>propertyName = GetPropertyName(propertyExpression);

    <span style="color: blue">if </span>(!dataErrors.ContainsKey(propertyName))
    {
        dataErrors[propertyName] = <span style="color: blue">new </span><span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;();
    }

    <span style="color: blue">if </span>(dataErrors[propertyName]
        .SingleOrDefault(e =&gt; e == errorText) == <span style="color: blue">null</span>)
        dataErrors[propertyName].Add(errorText);

    OnErrorsChanged(propertyName);
}

<span style="color: blue">protected void </span>ClearErrors&lt;T&gt;(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;T&gt;&gt; propertyExpression)
{

    <span style="color: blue">if </span>(propertyExpression == <span style="color: blue">null</span>)
        <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;propertyExpression&quot;</span>);

    <span style="color: blue">string </span>propertyName = GetPropertyName(propertyExpression);

    <span style="color: blue">if </span>(dataErrors.ContainsKey(propertyName)
        &amp;&amp; dataErrors[propertyName] != <span style="color: blue">null</span>)
        dataErrors.Remove(propertyName);

    OnErrorsChanged(propertyName);
}

<span style="color: blue">protected void </span>OnErrorsChanged&lt;T&gt;(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;T&gt;&gt; propertyExpression)
{
    <span style="color: blue">if </span>(propertyExpression == <span style="color: blue">null</span>)
        <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;propertyExpression&quot;</span>);

    <span style="color: blue">string </span>propertyName = GetPropertyName(propertyExpression);

    OnErrorsChanged(propertyName);
}

<span style="color: blue">private void </span>OnErrorsChanged(<span style="color: blue">string </span>propertyName)
{
    <span style="color: blue">if </span>(<span style="color: blue">string</span>.IsNullOrEmpty(propertyName))
        <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">&quot;propertyName&quot;</span>);

    <span style="color: blue">if </span>(ErrorsChanged != <span style="color: blue">null</span>)
    {
        ErrorsChanged(<span style="color: blue">this</span>, <span style="color: blue">new </span><span style="color: #2b91af">DataErrorsChangedEventArgs</span>(propertyName));
    }

}

<span style="color: blue">public event </span><span style="color: #2b91af">EventHandler</span>&lt;<span style="color: #2b91af">DataErrorsChangedEventArgs</span>&gt; ErrorsChanged;

<span style="color: blue">public </span><span style="color: #2b91af">IEnumerable </span>GetErrors(<span style="color: blue">string </span>propertyName)
{
    <span style="color: blue">if </span>(dataErrors.ContainsKey(propertyName))
    {
        <span style="color: blue">return </span>dataErrors[propertyName];
    }
    <span style="color: blue">return </span>dataErrors.Values;
}

<span style="color: blue">public bool </span>HasErrors
{
    <span style="color: blue">get
    </span>{
        <span style="color: blue">return </span>(<span style="color: blue">from </span>e <span style="color: blue">in </span>dataErrors
                <span style="color: blue">where </span>e.Value.Count &gt; 0
                <span style="color: blue">select </span>e).Count() &gt; 0;
    }
}</pre>
</div>
<p align="justify">Dans cette implémentation on retrouve bien les trois membres de l&#8217;interface à savoir: l&#8217;event ErrorsChanged, la méthode GetErrors et la propriété HasErrors.</p>
<p align="justify">Pour stocker les erreurs nous nous appuyons sur un dictionnaire. Chaque élément de ce dictionnaire est composé d&#8217;une clé correspondant au nom de la propriété en erreur et d&#8217;une valeur représentée par une liste de string pour y mettre les erreurs relatives&#160; à la propriété.</p>
<p align="justify">Maintenant, comme vous&#160; l&#8217;aurez certainement remarqué, on a également ajouté plusieurs méthodes:</p>
<p align="justify">Une première pour notifier un changement&#160; sur une erreur d&#8217;une propriété avec la méthode OnErrorsChanged. Cette méthode prend en paramètre une expression LINQ, nous évitant ainsi de passer le nom de la propriété sous forme de string. Cette technique permet d&#8217;éviter toute erreur dans le nommage de la propriété puisque l&#8217;erreur sera détectée à la compilation.</p>
<p align="justify">Une seconde méthode AddError pour ajouter une erreur relative à une propriété, dans le dictionnaire dataErrors. Cette méthode prend également une expression LINQ et une string représentant l&#8217;erreur.</p>
<p align="justify">Et enfin une dernière méthode pour supprimer les erreurs d&#8217;une propriété. Comme les deux dernières elle se base sur une expression LINQ.</p>
<p align="justify">OnErrorsChanged est appelée dans AddError et dans ClearErrors pour notifier les changements. Ces deux méthodes contiennent un appel à la méthode GetPropertyName. Vous pourrez trouver cette méthode dans le code lié au billet. Comme son nom l&#8217;indique elle permet d&#8217;extraire le nom de la propriété à partir de l&#8217;expression LINQ.</p>
<p align="justify">ModelBase implémente également INotifyPropertyChanged pour notifier le changement d&#8217;une propriété, mais le détail n&#8217;est pas présent dans le code ci-dessus.</p>
<p align="justify">Voilà cette classe est terminée. Voyons maintenant de plus près la classe User.</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">User </span>: <span style="color: #2b91af">ModelBase
 </span>{
     <span style="color: blue">private string </span>name;
     <span style="color: blue">public string </span>Name
     {
         <span style="color: blue">get </span>{ <span style="color: blue">return </span>name; }
         <span style="color: blue">set
         </span>{
             <span style="color: blue">if </span>(<span style="color: blue">value </span>!= name)
             {
                 ClearErrors(() =&gt; Name);

                 name = <span style="color: blue">value</span>;
                 ValidateUserName(<span style="color: blue">value</span>);
                 OnNotify(() =&gt; Name);
             }
         }
     }

     <span style="color: blue">private string </span>firstName;
     <span style="color: blue">public string </span>FirstName
     {
         <span style="color: blue">get </span>{ <span style="color: blue">return </span>firstName; }
         <span style="color: blue">set
         </span>{
             <span style="color: blue">if </span>(<span style="color: blue">value </span>!= firstName)
             {
                 firstName = <span style="color: blue">value</span>;
                 OnNotify(() =&gt; FirstName);
             }
         }
     }
 }</pre>
<p align="justify">A première vue on observe que la classe User hérite donc de ModelBase. Elle contient trois propriétés mais seule Name nous intéresse ici. Dans le setter avant d&#8217;assigner la nouvelle valeur, nous commençons par supprimer les erreurs liées à cette propriété, puis on appelle la méthode ValidateUserName en lui passant la nouvelle valeur, et enfin on notifie que la propriété est modifiée avec OnNotify provenant également de ModelBase.</p>
<p>Comme vous allez le voir avec le code ci-dessous, la méthode ValidateUserName fait appel à un webservice WCF pour vérifier côté serveur que le nouveau Name n&#8217;existe pas déjà.</p>
<pre class="code">UserService.<span style="color: #2b91af">UserServiceClient </span>proxy
    = <span style="color: blue">new </span>UserService.<span style="color: #2b91af">UserServiceClient</span>();
proxy.ExistsCompleted += (s, e) =&gt;
{
    <span style="color: blue">if </span>(e.Error != <span style="color: blue">null</span>)
    {
        <span style="color: blue">if </span>(e.Error <span style="color: blue">is </span><span style="color: #2b91af">FaultException</span>&lt;<span style="color: #2b91af">UserStoreFault</span>&gt;)
        {
            <span style="color: #2b91af">FaultException</span>&lt;<span style="color: #2b91af">UserStoreFault</span>&gt; exp =
                e.Error <span style="color: blue">as </span><span style="color: #2b91af">FaultException</span>&lt;<span style="color: #2b91af">UserStoreFault</span>&gt;;
            <span style="color: blue">if </span>(exp.Detail.Code == <span style="color: #2b91af">StoreFaultCodeEnum</span>.FileNotFoundException)
                AddError(() =&gt; Name,
                    <span style="color: #a31515">&quot;Base de données non disponible
                      </span>merci de réessayer plus tard<span style="color: #a31515">&quot;);

        </span>}

        <span style="color: blue">if </span>(e.Error <span style="color: blue">is </span><span style="color: #2b91af">FaultException</span>)
        {
            <span style="color: #2b91af">FaultException </span>exp =
                e.Error <span style="color: blue">as </span><span style="color: #2b91af">FaultException</span>;
            AddError(() =&gt; Name,
                <span style="color: #a31515">&quot;La vérification du username est
                 </span>impossible  pour le moment. Merci de réessayer plus tard<span style="color: #a31515">&quot;);
        </span>}
    }
    <span style="color: blue">else
    </span>{
        <span style="color: blue">string </span>message = <span style="color: #a31515">&quot;This name already exists&quot;</span>;
        <span style="color: blue">if </span>(e.Result)
        {
            AddError(() =&gt; Name, message);
        }
        <span style="color: blue">else
        </span>{
            OnErrorsChanged(() =&gt; Name);
        }
    }
};
proxy.ExistsAsync(name);</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Après avoir instancié le WebService, nous appelons la méthode Exists du service WCF de manière asynchrone. Côté serveur le service est chargé de vérifier que le name passé en paramètre n&#8217;existe pas déjà. Peu importe où les Users se trouvent: xml, base de données. Ce point n&#8217;est pas important pour le sujet de ce billet (Une implémentation du service est présente dans les sources liées au billet)</p>
<p>Une fois que le service a terminé son traitement le callback ExistCompleted est appelé. C&#8217;est dans cette méthode que nous allons faire la gestion d&#8217;erreur. Dans le cas où le webservice n&#8217;a pas levé d&#8217;erreur ie que e.Error est null, on vérifie la valeur retournée par la méthode Exists qui se trouve dans la propriété Result. Si Result à la valeur true, alors le Name existe déjà. Dans ce cas on appelle la méthode AddError détaillée plus haut, qui va se charger d&#8217;ajouter l&#8217;erreur dans le dictionnaire, puis de notifier le changement. Et voilà !!</p>
<p align="justify">Au passage, vous noterez la gestion d&#8217;erreur avec les FaultException si le WebService a levé une exception. Pour plus de détail, je vous invite à consulter ce <a href="http://blog.experida.fr/2010/12/18/fault-exception-avec-wcf-silverlight/">billet</a>.</p>
<p align="justify">Dernier point qui nous reste à voir, l&#8217;UI. Pour tester tout ce code, nous allons simplement créer une instance de User puis l&#8217;ajouter au DataContext de MainPage. Enfin dans&#160; MainPage, nous allons ajouter une TextBox et nous binder sur la propriété Name. Pour que les erreurs puissent s&#8217;afficher, il ne faut pas oublier d&#8217;assigner la valeur true à la propriété ValidatesOnNotifyDataErrors de l&#8217;élément Binding et le tour est joué.</p>
<pre class="code"><span style="color: #2b91af">User </span>newUser = <span style="color: blue">new </span><span style="color: #2b91af">User</span>();
<span style="color: blue">this</span>.DataContext = newUser;</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">TextBox </span><span style="color: red">Text</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">Binding </span><span style="color: red">Name</span><span style="color: blue">,</span><span style="color: red">ValidatesOnNotifyDataErrors</span><span style="color: blue">=True,</span><span style="color: red">Mode</span><span style="color: blue">=TwoWay}&quot; </span><span style="color: red">Width</span><span style="color: blue">=&quot;125&quot; </span><span style="color: red">Height</span><span style="color: blue">=&quot;25&quot; /&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Sur le serveur les Users se trouvent actuellement dans un fichier xml. Si vous entrez une valeur Name différente de celles&#160; existantes, aucune erreur ne s&#8217;affichera. Dans le cas contraire, vous verrez apparaître un tooltip rouge avec le détail de l&#8217;erreur.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Users</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">User</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">UserName</span><span style="color: blue">&gt;</span>alex<span style="color: blue">&lt;/</span><span style="color: #a31515">UserName</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">FirstName</span><span style="color: blue">&gt;</span>Alexandre<span style="color: blue">&lt;/</span><span style="color: #a31515">FirstName</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">LastName</span><span style="color: blue">&gt;</span>Arnaudet<span style="color: blue">&lt;/</span><span style="color: #a31515">LastName</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">User</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">User</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">UserName</span><span style="color: blue">&gt;</span>al<span style="color: blue">&lt;/</span><span style="color: #a31515">UserName</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">FirstName</span><span style="color: blue">&gt;</span>Alexandre<span style="color: blue">&lt;/</span><span style="color: #a31515">FirstName</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">LastName</span><span style="color: blue">&gt;</span>Arnaudet<span style="color: blue">&lt;/</span><span style="color: #a31515">LastName</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">User</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">Users</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://blog.experida.fr/wp-content/uploads/2011/01/image.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2011/01/image_thumb.png" width="359" height="124" /></a> </p>
<p>&#160;</p>
<p align="justify">Retrouvez l&#8217;intégralité du code <a href="http://blog.experida.fr/wp-content/uploads/2011/01/NotifyDataErrorInfo.zip">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2011/01/04/silverlight-4-validation-de-donnees-avec-inotifydataerrorinfo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fault Exception avec WCF / Silverlight</title>
		<link>http://blog.experida.fr/2010/12/18/fault-exception-avec-wcf-silverlight/</link>
		<comments>http://blog.experida.fr/2010/12/18/fault-exception-avec-wcf-silverlight/#comments</comments>
		<pubDate>Sat, 18 Dec 2010 17:02:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WCF]]></category>
		<category><![CDATA[Fault]]></category>
		<category><![CDATA[FaultException]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/12/18/fault-exception-avec-wcf-silverlight/</guid>
		<description><![CDATA[Par défaut, lorsqu&#8217;une exception est levée dans une méthode d&#8217;un service, le contenu de l&#8217;exception n&#8217;est pas envoyé au client qui consomme le service. Lors de la phase de développement, une pratique commune est de modifier la behavior associée au service en ajoutant l&#8217;élément serviceDebugincludeExceptionDetailInFaults à true pour que les erreurs puissent remonter jusqu&#8217;au client. [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Par défaut, lorsqu&#8217;une exception est levée dans une méthode d&#8217;un service, le contenu de l&#8217;exception n&#8217;est pas envoyé au client qui consomme le service.</p>
<p align="justify">Lors de la phase de développement, une pratique commune est de modifier la behavior associée au service en ajoutant l&#8217;élément <strong>serviceDebugincludeExceptionDetailInFaults </strong>à <strong>true</strong> pour que les erreurs puissent remonter jusqu&#8217;au client. Bien entendu, n&#8217;oubliez pas de désactiver cette option lors de la livraison de votre service en production.</p>
<p> <span id="more-267"></span>
<p align="justify">Si vous avez fait attention, vous aurez remarqué que le dernier mot de l&#8217;élément cité ci-dessus est Fault.&#160; Une <strong>Fault</strong> est une classe sérialisable permettant de faire transiter entre le serveur et le client des informations structurées concernant l&#8217;erreur qui est arrivée.</p>
<p align="justify">Pour utiliser les Faults, il vous suffit d&#8217;ajouter l&#8217;attribut <strong>FaultContract </strong>sur une opération identifiée par l&#8217;attribut <strong>OperationContract</strong> et d&#8217;y passer le type de fault gérée. A noter qu&#8217;on peut renvoyer des Faults aussi bien technique que métier.</p>
<p align="justify">Codons un exemple pour illustrer ce que nous venons de dire.</p>
<p align="justify">Commencez par créer une solution et ajoutez-y une librairie WCF. Dans cette exemple nous allons considérer que notre service a une seule opération permettant de retourner un customer. </p>
<p align="justify">L&#8217;élément doit être sérialisable et est représenté par les trois propriétés suivantes:</p>
<p> <a href="http://11011.net/software/vspaste"></a>
<pre class="code">[<span style="color: #2b91af">DataContract</span>]
   <span style="color: blue">public class </span><span style="color: #2b91af">Customer
   </span>{
       [<span style="color: #2b91af">DataMember</span>]
       <span style="color: blue">public int </span>Id { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
       [<span style="color: #2b91af">DataMember</span>]
       <span style="color: blue">public string </span>LastName { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
       [<span style="color: #2b91af">DataMember</span>]
       <span style="color: blue">public string </span>FirstName { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Pour définir le service, nous allons dans un premier temps créer le contrat et y ajouter l&#8217;opération GetCustomer</p>
<pre class="code">[<span style="color: #2b91af">ServiceContract</span>]
   <span style="color: blue">public interface </span><span style="color: #2b91af">ICustomerService
   </span>{
       [<span style="color: #2b91af">OperationContract</span>]
       [<span style="color: #2b91af">FaultContract</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">CustomerNotFoundFault</span>))]
       <span style="color: #2b91af">Customer </span>GetCustomer(<span style="color: blue">int </span>projectId);
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Ensuite ajoutez une implémentation pour ce service</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">CustomerService </span>: <span style="color: #2b91af">ICustomerService
   </span>{
       <span style="color: blue">private </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Customer</span>&gt; Customers = <span style="color: blue">new </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Customer</span>&gt;();

       <span style="color: blue">public </span>CustomerService()
       {
           Customers.Add(
               <span style="color: blue">new </span><span style="color: #2b91af">Customer
               </span>{
                   Id = 1,
                   FirstName = <span style="color: #a31515">&quot;FirstName1&quot;</span>,
                   LastName = <span style="color: #a31515">&quot;LastName1&quot;
               </span>});
           Customers.Add(
               <span style="color: blue">new </span><span style="color: #2b91af">Customer
               </span>{
                   Id = 2,
                   FirstName = <span style="color: #a31515">&quot;FirstName2&quot;</span>,
                   LastName = <span style="color: #a31515">&quot;LastName2&quot;
               </span>});
       }

       <span style="color: blue">public </span><span style="color: #2b91af">Customer </span>GetCustomer(<span style="color: blue">int </span>projectId)
       {
           <span style="color: blue">throw new </span><span style="color: #2b91af">Exception</span>(<span style="color: #a31515">&quot;test exception&quot;</span>);
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Le service contient une collection de customer dont nous nous servirons plus tard. Bien entendu dans un projet réel, vous aurez une DAL. J&#8217;ai tout codé dans le service pour des raisons de simplicité pour la démo.</p>
<p align="justify">Afin de tester que par défaut aucune information sur le contenu de l&#8217;exception est envoyée au client, j&#8217;ai ajouté un throw new Exception.</p>
<p align="justify">Ajoutez une application console pour tester le service, puis créez le proxy et appelez l&#8217;opération GetCustomer</p>
<pre class="code"><span style="color: blue">static void </span>Main(<span style="color: blue">string</span>[] args)
        {
            <span style="color: #2b91af">CustomerServiceClient </span>client = <span style="color: blue">new </span><span style="color: #2b91af">CustomerServiceClient</span>();
            client.GetCustomer(-1);
        }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Vous devriez obtenir l&#8217;écran suivant:</p>
<p align="justify"><a href="http://blog.experida.fr/wp-content/uploads/2010/12/image.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/12/image_thumb.png" width="365" height="252" /></a> </p>
<p align="justify">On se rend compte qu&#8217;une FaultException générique a été créée par WCF pour nous suite à une exception sur le serveur. Cependant nous n&#8217;avons aucune information détaillée sur la raison réelle de l&#8217;exception.</p>
<p>En effet, si vous jetez une petit coup d&#8217;œil dans le fichier de configuration serveur, vous remarquerez que <strong>includeExceptionDetailInFault</strong> est à false.</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">serviceDebug </span><span style="color: red">includeExceptionDetailInFaults</span><span style="color: blue">=</span>&quot;<span style="color: blue">False</span>&quot; <span style="color: blue">/&gt;
</span></pre>
<p>Pour aller jusqu&#8217;au bout de ce test, changez la valeur en la passant à true et exécutez à nouveau l&#8217;application console.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/12/image1.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/12/image_thumb1.png" width="358" height="203" /></a></p>
<p align="justify">Cette fois, le contenu de l&#8217;exception a bien été envoyé au client. Bien entendu pour une application destinée à être utilisée en production nous allons laisser cette valeur à false et utiliser des Faults dites déclarées.</p>
<p align="justify">Mettons à jour le code pour refléter l&#8217;utilisation des Faults. Pour cela posons-nous la question suivante :</p>
<p align="justify">Quelles sont les erreurs pouvant être levées lors de l&#8217;appel de la méthode GetCustomer ? Pour ne pas compliquer les choses nous allons nous limiter à:</p>
<ul>
<li>
<div align="justify">Id customer non valide</div>
</li>
<li>
<div align="justify">customer non trouvé.</div>
</li>
</ul>
<p align="justify">Pour matérialiser ces deux points nous allons utiliser les classes FaultException pour l&#8217;Id non valide, et une FaultException personnalisée que nous nommerons CustomerNotFoundFault pour l&#8217;utilisateur non trouvé. </p>
<p align="justify">FaultException est nativement gérée par WCF. Pour indiquer qu&#8217;une CustomerNotFoundFault peut être levée dans l&#8217;opération, nous devons ajouter l&#8217;attribut FaultContract au niveau de la déclaration de l&#8217;opération.</p>
<pre class="code">    [<span style="color: #2b91af">OperationContract</span>]
    [<span style="color: #2b91af">FaultContract</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">CustomerNotFoundFault</span>))]
    <span style="color: #2b91af">Customer </span>GetCustomer(<span style="color: blue">int </span>projectId);</pre>
<pre class="code">[<span style="color: #2b91af">DataContract</span>]
   <span style="color: blue">public class </span><span style="color: #2b91af">CustomerNotFoundFault
   </span>{
       [<span style="color: #2b91af">DataMember</span>]
       <span style="color: blue">public string </span>ErrorMessage { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

       [<span style="color: #2b91af">DataMember</span>]
       <span style="color: blue">public int </span>Id { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Si vous omettez cet attribut, ce type de FaultException ne sera tout simplement pas exploitable par le client du service.</p>
<p>Pour résumer ces quelques lignes voici le code correspondant:</p>
<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">Customer </span>GetCustomer(<span style="color: blue">int </span>Id)
 {
    <span style="color: #2b91af">FaultCode </span>faultCode;
    <span style="color: #2b91af">FaultReason </span>faultReason;

    <span style="color: #2b91af">Customer </span>cust = <span style="color: blue">null</span>;

    <span style="color: blue">if </span>(Id &lt; 1)
    {
       faultReason = <span style="color: blue">new </span><span style="color: #2b91af">FaultReason</span>(<span style="color: #a31515">&quot;Invalid Customer Id&quot;</span>);
       faultCode = <span style="color: #2b91af">FaultCode
          </span>.CreateSenderFaultCode(<span style="color: #a31515">&quot;InvalidRequest&quot;</span>, <span style="color: blue">this</span>.GetType().FullName);
           <span style="color: blue">throw new </span><span style="color: #2b91af">FaultException</span>(faultReason, faultCode);
    }

    cust = Customers.FirstOrDefault(c =&gt; c.Id == Id);
    <span style="color: blue">if </span>(cust == <span style="color: blue">null</span>)
    {
     <span style="color: #2b91af">CustomerNotFoundFault </span>fault = <span style="color: blue">new </span><span style="color: #2b91af">CustomerNotFoundFault
     </span>{
       Id = Id,
       ErrorMessage = <span style="color: blue">string</span>.Format(<span style="color: #a31515">&quot;No Customer with id {0}&quot;</span>, Id)
     };
         <span style="color: blue">throw new
          </span><span style="color: #2b91af">FaultException</span>&lt;<span style="color: #2b91af">CustomerNotFoundFault</span>&gt;(fault, fault.ErrorMessage);
    }

    <span style="color: blue">return </span>cust;
 }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Vous constaterez également l&#8217;utilisation de FaultReason permettant de décrire l&#8217;erreur et FaultCode plus utilisé pour identifier la source, le type de l&#8217;erreur.</p>
<p align="justify">Pour voir maintenant ce qui arrive côté client, effectuons de nouveaux tests, avec pour commencer, une valeur inférieure à 0.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/12/image2.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/12/image_thumb2.png" width="334" height="175" /></a> </p>
<p align="justify">On voit que cette fois-ci le client reçoit une FaultException. Au niveau du contenu, on retrouve la FaultReason ainsi que le Fault Code qui ont été spécifiés côté serveur.</p>
<p align="justify">Dans le code ci-dessous, on voit que la propriété IsSenderFault est à true. En effet le serveur a précisé qu&#8217;il s&#8217;agissait d&#8217;une erreur due au client. En l&#8217;occurrence, il s&#8217;agit ici de l&#8217;id customer qui n&#8217;est pas valide.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/12/image3.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/12/image_thumb3.png" width="495" height="270" /></a> </p>
<p align="justify">Pour la seconde erreur, à savoir un customer non trouvé, nous venons de voir qu&#8217;une exception <strong>FaultException&lt;CustomerNotFoundFault&gt;</strong> était levée.</p>
<p align="justify">Coté client il vous suffit de mettre un try / catch englobant l&#8217;appel au service avec une gestion d&#8217;erreur du plus spécifique au plus général, c&#8217;est à dire d&#8217;abord<strong>&#160; FaultException&lt;CustomerNotFoundFault&gt;</strong> puis&#160; <strong>FaultException</strong>. Une fois l&#8217;erreur attrapée vous pourrez prendre&#160; une décision sur le comportement que le client doit avoir.</p>
<p align="justify">Nous venons de voir globalement comment fonctionnaient les FaultException avec WCF et une application cliente de type console.</p>
<p align="justify">Dans le cadre d&#8217;un client comme silverlight, quelques développements supplémentaires sont nécessaires. </p>
<p align="justify">En effet par défaut lorsqu&#8217;une erreur arrive côté serveur une erreur 500 est envoyée au client. Il sait qu&#8217;il y&#160; a eu une erreur mais sans plus de détail. </p>
<p align="justify">Le message exacte est :&quot; The remote server returned an error: NotFound&quot;</p>
<p align="justify"><a href="http://blog.experida.fr/wp-content/uploads/2010/12/image4.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/12/image_thumb4.png" width="408" height="201" /></a> </p>
<p align="justify">Une solution possible est donc d&#8217;intercepter côté serveur toute Fault et de modifier le code 500 renvoyé au client par un code 200 qui dans le cadre d&#8217;une réponse HTTP signifie que tout s&#8217;est bien passé. Le client Silverlight pourra ainsi accéder à la Fault.</p>
<p align="justify">Pour y parvenir, nous allons créer une behavior qui sera associée au EndPoint. Cette behavior doit hériter de <strong>BehaviorExtensionElement </strong>et implémenter l&#8217;interface <strong>IEndPointBehavior.</strong></p>
<ul>
<li>
<div align="justify">BehaviorExtensionElement représente un élément de configuration pour paramétrer une extension</div>
</li>
<li>
<div align="justify">IEndPointBehavior apporte des méthodes pour modifier le comportement du EndPoint</div>
</li>
</ul>
<p align="justify">Parmi les méthodes disponibles via l&#8217;interface IEndPointBehavior, une nous intéresse plus particulièrement ici. Il s&#8217;agit de la méthode <strong>ApplyDispatcherBehavior </strong>qui va nous permettre d&#8217;étendre la manière dont réagit le service.</p>
<div align="justify">
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">FaultBehaviour </span>: <span style="color: #2b91af">BehaviorExtensionElement</span>, <span style="color: #2b91af">IEndpointBehavior
   </span>{
       <span style="color: blue">public void </span>ApplyDispatchBehavior
           (<span style="color: #2b91af">ServiceEndpoint </span>endpoint, <span style="color: #2b91af">EndpointDispatcher </span>endpointDispatcher)
       {
           <span style="color: #2b91af">SilverlightFaultMessageInspector </span>inspector =
               <span style="color: blue">new </span><span style="color: #2b91af">SilverlightFaultMessageInspector</span>();
           endpointDispatcher
               .DispatchRuntime.MessageInspectors.Add(inspector);
       }</pre>
</div>
<p align="justify">Dans cette méthode on retrouve la création d&#8217;une classe implémentant l&#8217;interface <strong>IDispatchMessageInspector</strong> dont le but est comme son nom le laisse entendre, d&#8217;intercepter le message transitant pour l&#8217;analyser et / ou le modifier. </p>
<p align="justify">Rappelons que nous souhaitons modifier le code http renvoyé au client. Pour cela implémentons la méthode <strong>BeforeSendReply</strong> de IDispatchMessageInspector.</p>
<pre class="code"><span style="color: blue">public void </span>BeforeSendReply(<span style="color: blue">ref </span><span style="color: #2b91af">Message </span>reply, <span style="color: blue">object </span>correlationState)
 {
  <span style="color: blue">if </span>(reply.IsFault)
  {
   <span style="color: #2b91af">HttpResponseMessageProperty </span>property = <span style="color: blue">new </span><span style="color: #2b91af">HttpResponseMessageProperty</span>();

                   <span style="color: green">// Change response code to 200 (default: 500)
      </span>property.StatusCode = System.Net.<span style="color: #2b91af">HttpStatusCode</span>.OK;

      reply.Properties[<span style="color: #2b91af">HttpResponseMessageProperty</span>.Name] = property;
   }
  }</pre>
</p>
<p>Dans ce code, nous voyons clairement, que si la réponse est une FaultException, nous passons le code de status à Ok: HTTP 200.</p>
<p>Afin que cette extension puisse être utilisée, il nous reste un dernier point à voir. Mettre à jour le fichier de configuration, en ajoutant l&#8217;extension et en l&#8217;assignant au endpoint correspondant.</p>
<p>Pour cela dans la section <strong>ServiceModel</strong> du web.config, commencez par déclarer l&#8217;extension.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">extensions</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">behaviorExtensions</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">add </span><span style="color: red">name</span><span style="color: blue">=</span>&quot;<span style="color: blue">silverlightFaults</span>&quot;
             <span style="color: red">type</span><span style="color: blue">=</span>&quot;<span style="color: blue">SilverlightApplicationFault.Web.FaultBehaviour,
                  SilverlightApplicationFault.Web,
                  Version=1.0.0.0,
                  Culture=neutral,
                  PublicKeyToken=null</span>&quot;<span style="color: blue">/&gt;
      &lt;/</span><span style="color: #a31515">behaviorExtensions</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">extensions</span><span style="color: blue">&gt;
</span></pre>
<p>Ajoutez ensuite la behavior dans la section <strong>behaviors</strong>:</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">endpointBehaviors</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">behavior </span><span style="color: red">name</span><span style="color: blue">=</span>&quot;<span style="color: blue">SilverlightFaultBehavior</span>&quot;<span style="color: blue">&gt;
          &lt;</span><span style="color: #a31515">silverlightFaults</span><span style="color: blue">/&gt;
        &lt;/</span><span style="color: #a31515">behavior</span><span style="color: blue">&gt;
      &lt;/</span><span style="color: #a31515">endpointBehaviors</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Enfin reconfigurez le endpoint pour utiliser la behavior que l&#8217;on vient d&#8217;ajouter.</p>
<pre class="code">  <span style="color: blue">&lt;</span><span style="color: #a31515">endpoint </span><span style="color: red">address</span><span style="color: blue">=</span>&quot;&quot; <span style="color: red">binding</span><span style="color: blue">=</span>&quot;<span style="color: blue">customBinding</span>&quot;
    <span style="color: red">bindingConfiguration</span><span style="color: blue">=</span>&quot;<span style="color: blue">SilverlightApplicationFault.Web
      .CustomerService.customBinding0</span>&quot;
    <span style="color: red">contract</span><span style="color: blue">=</span>&quot;<span style="color: blue">SilverlightApplicationFault.Web.ICustomerService</span>&quot;
    <span style="color: red">behaviorConfiguration</span><span style="color: blue">=</span>&quot;<span style="color: blue">SilverlightFaultBehavior</span>&quot; <span style="color: blue">/&gt;
</span></pre>
<p>La configuration est à présent terminée.</p>
<p>Relancez l&#8217;application, vous devriez voir la <strong>Fault</strong> remontée côté client.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/12/image5.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/12/image_thumb5.png" width="568" height="133" /></a> </p>
<p>Vous pouvez télécharger les sources <a href="http://blog.experida.fr/wp-content/uploads/2010/12/SilverlightApplicationFault.zip">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/12/18/fault-exception-avec-wcf-silverlight/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Erreur x80020101 avec Silverlight 3, SSL sous IE 6</title>
		<link>http://blog.experida.fr/2010/11/21/erreur-x80020101-avec-silverlight-3-ssl-sous-ie-6/</link>
		<comments>http://blog.experida.fr/2010/11/21/erreur-x80020101-avec-silverlight-3-ssl-sous-ie-6/#comments</comments>
		<pubDate>Sun, 21 Nov 2010 16:46:59 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[IIS7]]></category>
		<category><![CDATA[Silverlight 3]]></category>
		<category><![CDATA[SSL]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/11/21/erreur-x80020101-avec-silverlight-3-ssl-sous-ie-6/</guid>
		<description><![CDATA[Depuis peu de temps je suis passé sur le développement d&#8217;une application Silverlight 3 pour le client où je suis actuellement. Nous avons réalisé les premiers développements sans encombre et ces derniers jours nous avons décidé de déployer l&#8217;application sur un serveur, afin que le client puisse tester et prendre en main l&#8217;application tout au [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Depuis peu de temps je suis passé sur le développement d&#8217;une application Silverlight 3 pour le client où je suis actuellement.</p>
<p align="justify">Nous avons réalisé les premiers développements sans encombre et ces derniers jours nous avons décidé de déployer l&#8217;application sur un serveur, afin que le client puisse tester et prendre en main l&#8217;application tout au long de son développement.</p>
<p> <span id="more-253"></span>
<p align="justify">Le serveur sur lequel l&#8217;application est déployée est Windows Server 2008, le tout tournant sous IIS 7. </p>
<p align="justify">Pour des raisons de sécurité, nous avons également configuré le SSL sur l&#8217;intégralité des pages de l&#8217;application.</p>
<p align="justify">Le déploiement étant terminé, la phase de teste pointe le bout de son nez. Le client utilise encore IE 6. Nous démarrons donc ce navigateur, entrons l&#8217;url de l&#8217;application en question et là une erreur apparaît à l&#8217;écran. L&#8217;erreur n&#8217;est absolument pas explicite. La seule information que nous ayons étant le code suivant: 0&#215;80020101, sans plus de détail.</p>
<p align="justify">Après quelques recherches sur le net, je ne comprends toujours pas ce qui provoque cette erreur. Depuis un autre ordinateur que le mien, je lance l&#8217;application sous IE 7 et là aucun soucis. Idem avec la dernière version de Firefox.</p>
<p align="justify">Ne sachant toujours pas où se situe le problème, j&#8217;essaie de désactiver le SSL et là oh miracle je n&#8217;ai plus d&#8217;erreur. Suite à de nouvelles recherches sur le web, je remarque que plusieurs développeurs indiquent de faire attention à bien préciser la balise <strong>src</strong> sur les éléments HTML possédant cette propriété.&#160; </p>
<p align="justify">Sachant que l&#8217;intégralité de l&#8217;application est en silverlight, la seule page pouvant contenir un élément HTML est donc la page hôte qui contient justement notre application. Et là que vois-je: une Iframe. J&#8217;ajoute donc la propriété src et la fait pointer faire une page html ne contenant strictement rien -&gt; &lt;iframe src=&quot;./page.html&quot; &#8230;./&gt;</p>
<p align="justify">Après cette modification, je relance l&#8217;application, toujours sans SSL pour vérifier le bon fonctionnement et tout est Ok. Je réactive donc le SSL sur IIS et là super tout fonctionne sans erreur.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/11/21/erreur-x80020101-avec-silverlight-3-ssl-sous-ie-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>D&#233;ploiement des binaires RIA Services Beta</title>
		<link>http://blog.experida.fr/2010/11/19/deploiement-des-binaires-ria-services-beta/</link>
		<comments>http://blog.experida.fr/2010/11/19/deploiement-des-binaires-ria-services-beta/#comments</comments>
		<pubDate>Thu, 18 Nov 2010 22:07:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[déploiement]]></category>
		<category><![CDATA[RIA Services]]></category>
		<category><![CDATA[Silverlight 3]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/11/19/deploiement-des-binaires-ria-services-beta/</guid>
		<description><![CDATA[Lorsque Microsoft a mis à disposition la première version des RIA Services, l&#8217;installation des binaires se faisait via un fichier MSI. Avant de procéder à l&#8217;installation des binaires dans le GAC, le MSI vérifiait certains pré requis comme l&#8217;installation de Visual Studio 2008 et les Silverlight tools Pendant la phase de développement d&#8217;un projet cela [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Lorsque Microsoft a mis à disposition la première version des RIA Services, l&#8217;installation des binaires se faisait via un fichier MSI. Avant de procéder à l&#8217;installation des binaires dans le GAC, le MSI vérifiait certains pré requis comme l&#8217;installation de Visual Studio 2008 et les Silverlight tools</p>
<p align="justify">Pendant la phase de développement d&#8217;un projet cela ne pose aucun problème, puisque ces outils sont nécessaires pour le développement, mais comment procéder pour le déploiement&#160; sur un serveur.</p>
<p align="justify"><u>Deux possibilités existent:</u></p>
<ul>
<li>
<div align="justify">La première consiste simplement à passer la propriété <strong>Copy Local</strong> des références RIA Services à <strong>true</strong>. Ainsi au moment de la compilation les binaires seront copiés dans le dossier bin. Il ne sera donc pas nécessaire d&#8217;utiliser un setup quelconque pour les installer dans le GAC.</div>
</li>
<li>
<div align="justify">La deuxième solution est d&#8217;utiliser le même MSI que pour l&#8217;installation sur la machine de développement mais en ligne de commande avec les paramètres suivants: <strong>msiexec /i RIAServices.msi SERVER=true. </strong>En procédant ainsi, les binaires sont déployés dans le GAC et le MSI ne fait plus attention aux pré requis.</div>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/11/19/deploiement-des-binaires-ria-services-beta/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Utilisation d&#8217;un fichier de ressources resx avec Silverlight 4 et les RIA Services</title>
		<link>http://blog.experida.fr/2010/11/14/utilisation-dun-fichier-de-ressource-resx-avec-silverlight-4-et-les-ria-services/</link>
		<comments>http://blog.experida.fr/2010/11/14/utilisation-dun-fichier-de-ressource-resx-avec-silverlight-4-et-les-ria-services/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 22:32:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Resource]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/11/15/utilisation-dun-fichier-de-ressource-resx-avec-silverlight-4-et-les-ria-services/</guid>
		<description><![CDATA[Lorsque vous créez des entités côté serveur (POCO, EntityFramework&#8230;.), vous avez la possibilité via des attributs provenant notamment de System.ComponentModel.DataAnnotations, d&#8217;indiquer les propriétés obligatoires, leur format. Vous pouvez également surcharger le nom la propriété qui sera affiché à l&#8217;écran. Prenons un exemple simple. Commençons par créer une classe basique User avec trois propriétés: UserId LastName [...]]]></description>
			<content:encoded><![CDATA[<p>Lorsque vous créez des entités côté serveur (POCO, EntityFramework&#8230;.), vous avez la possibilité via des attributs provenant notamment de <strong>System.ComponentModel.DataAnnotations</strong>, d&#8217;indiquer les propriétés obligatoires, leur format. Vous pouvez également surcharger le nom la propriété qui sera affiché à l&#8217;écran.</p>
<p>Prenons un exemple simple.</p>
<p><span id="more-248"></span>Commençons par créer une classe basique User avec trois propriétés:</p>
<ul>
<li>
<div>UserId</div>
</li>
<li>
<div>LastName</div>
</li>
<li>
<div>FirstName</div>
</li>
</ul>
<p>Une fois ceci fait, ajoutez une référence sur System.CompoenentModel.DataAnnotations et placez l&#8217;attribut Display sur chacune des propriétés. Cet attribut contient un certain nombre de propriétés, mais seulement deux nous intéressent ici: <strong>Name</strong> et <strong>ResourceType.</strong></p>
<p>Comme vous l&#8217;aurez certainement compris, le nom que l&#8217;on veut affecter à chacune de nos propriétés peut être stocké dans un fichier de ressources dont l&#8217;extension est .resx</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">User </span>:   <span style="color: #2b91af;">INotifyPropertyChanged
    </span>{
        [<span style="color: #2b91af;">Key</span>]
        [<span style="color: #2b91af;">Display</span>(Name = <span style="color: #a31515;">"UserId"</span>,
            ResourceType = <span style="color: blue;">typeof</span>(Resources.<span style="color: #2b91af;">ResourcesApplication</span>))]
        <span style="color: blue;">public int </span>UserId { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

        [<span style="color: #2b91af;">Display</span>(Name=<span style="color: #a31515;">"FirstName"</span>,
            ResourceType=<span style="color: blue;">typeof</span>(Resources.<span style="color: #2b91af;">ResourcesApplication</span>))]
        <span style="color: blue;">public string </span>FirstName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

         [<span style="color: #2b91af;">Display</span>(Name=<span style="color: #a31515;">"LastName"</span>,
             ResourceType = <span style="color: blue;">typeof</span>(Resources.<span style="color: #2b91af;">ResourcesApplication</span>))]
        <span style="color: blue;">public string </span>LastName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

        <span style="color: blue;">public event </span><span style="color: #2b91af;">PropertyChangedEventHandler </span>PropertyChanged;

        <span style="color: blue;">public void </span>Notify(<span style="color: blue;">string </span>propertyName)
        {
            <span style="color: blue;">if </span>(<span style="color: blue;">string</span>.IsNullOrEmpty(propertyName))
                <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"propertyName"</span>);

            <span style="color: blue;">if </span>(PropertyChanged != <span style="color: blue;">null</span>)
                PropertyChanged(<span style="color: blue;">this</span>,
                    <span style="color: blue;">new </span><span style="color: #2b91af;">PropertyChangedEventArgs</span>(propertyName));
        }
    }</pre>
<p> </p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/11/image.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/11/image_thumb.png" border="0" alt="image" width="392" height="157" /></a></p>
<p>A l&#8217;aide d&#8217;un DomainService, nous allons maintenant exposer côté client l&#8217;entité User. Je vous propose ici d&#8217;ajouter une méthode GetUsers qui comme son nom l&#8217;indique, permettra de récupérer une collection de User.</p>
<div>
<pre class="code">[<span style="color: #2b91af;">EnableClientAccess</span>()]
    <span style="color: blue;">public class </span><span style="color: #2b91af;">UserDomainService </span>: <span style="color: #2b91af;">DomainService
    </span>{
        <span style="color: blue;">private static </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">User</span>&gt; users;

        <span style="color: blue;">public </span>UserDomainService()
        {
            users = <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">User</span>&gt;();
            users.Add(<span style="color: blue;">new </span><span style="color: #2b91af;">User
            </span>{
                UserId = 1,
                LastName = <span style="color: #a31515;">"Arnaudet"</span>,
                FirstName = <span style="color: #a31515;">"Alexandre"
            </span>});
            users.Add(<span style="color: blue;">new </span><span style="color: #2b91af;">User
            </span>{
                UserId = 2,
                LastName = <span style="color: #a31515;">"Vanheren"</span>,
                FirstName = <span style="color: #a31515;">"Anne-Sophie"
            </span>});
        }

        <span style="color: blue;">public </span><span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">User</span>&gt; GetUsers()
        {
            <span style="color: blue;">return </span>users;
        }

<strong>    }
</strong></pre>
</div>
<p><strong> </strong></p>
<p>Si à cet instant vous compilez l&#8217;application, vous allez obtenir une erreur provenant du fichier auto généré côté client qui contient le Model et donc notre entité User. Ce fichier est facilement identifiable de part son extension &#8220;.g.cs&#8221;, uniquement visible dans la solution si vous sélectionnez le bouton Show All Files.</p>
<p>Pourquoi cette erreur ? Tout simplement parce que les RIA Services ne propagent pas automatiquement les fichiers de ressources du serveur vers le client.</p>
<p>Quelle solution avons-nous pour palier à ce manque ?</p>
<p>Vous pourriez créer un fichier de ressource côté serveur et un fichier de ressource côté client, mais dans ce cas là, vous aurez deux fichiers à maintenir. Cette solution n&#8217;est donc pas envisageable.</p>
<p>Une solution possible est d&#8217;ajouter le fichier de ressource en tant que fichier lié.</p>
<p>Pour cela créez un dossier dans votre application Silverlight, puis ajoutez les ressources en procédant de la manière suivante:</p>
<ul>
<li>
<ul>
<li>
<div>Sélectionnez le dossier où vous souhaitez ajouter le fichier de ressource</div>
</li>
<li>
<div>Faites &#8220;Ajouter un item existant&#8221;</div>
</li>
<li>
<div>Une fois la fenêtre ouverte, parcourez les dossiers jusqu&#8217;à localiser la ressource serveur</div>
</li>
<li>
<div>Sélectionnez le fichier resx et le le fichier designer.cs</div>
</li>
<li>
<div>Cliquez sur la flèche du bouton &#8220;Add&#8221; et choisissez &#8220;Add as link&#8221;</div>
</li>
</ul>
</li>
</ul>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/11/image1.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/11/image_thumb1.png" border="0" alt="image" width="240" height="115" /></a> Reprenons notre exemple avec la classe User et son DomainService associé. Dans le projet Silverlight, nous pouvons ajouter une vue avec un contrôle DataForm. Enfin via le UserDomainContext, nous récupérons et associons les données au DataForm.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">form</span><span style="color: blue;">:</span><span style="color: #a31515;">DataForm </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="DataForm" </span><span style="color: red;">AutoGenerateFields</span><span style="color: blue;">="True"/&gt;
</span></pre>
<pre class="code"><span style="color: #2b91af;">UserDomainContext </span>ctx = <span style="color: blue;">new </span><span style="color: #2b91af;">UserDomainContext</span>();
ctx.Load(ctx.GetUsersQuery(),(u)=&gt;DataForm.ItemsSource = u.AllEntities,<span style="color: blue;">null</span>);</pre>
<p>Lancez l&#8217;application et vous devriez maintenant voir les données, avec les labels provenant du fichier de ressource.</p>
<p><span style="text-decoration: underline;">Remarque:</span> au runtime, le Framework génère un nom de fichier différent du nom avec le .resx. Par exemple pour notre fichier ResourcesApplication.resx, le nom généré sera &#8220;SilverlightApplicationTestResources.Web.Resources.ResourcesApplication.resources&#8221;, avec &#8220;SilverlightApplicationTestResources.Web&#8221; qui correspond au root namespace du projet et &#8220;Resources&#8221; au nom du sous dossier qui contient notre fichier resx.</p>
<p>Côté client, vous devez respecter, la même arborescence sous peine d&#8217;avoir une exception au runtime</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/11/image2.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/11/image_thumb2.png" border="0" alt="image" width="488" height="126" /></a> </p>
<p>Pour forcer le nom du fichier qui sera utilisé au runtime, une solution est d&#8217;éditer le csproj manuellement en ajoutant l&#8217;élément logicalName dans EmbededResource.</p>
<pre class="code">  <span style="color: blue;">&lt;</span><span style="color: #a31515;">EmbeddedResource
      </span><span style="color: red;">Include</span><span style="color: blue;">=</span>"<span style="color: blue;">..\SilverlightApplicationTestResources.Web
        \Resources\ResourcesApplication.resx</span>"<span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">Link</span><span style="color: blue;">&gt;</span>Links\ResourcesApplication.resx<span style="color: blue;">&lt;/</span><span style="color: #a31515;">Link</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">LogicalName</span><span style="color: blue;">&gt;</span>SilverlightApplicationTestResources.Web
        .Resources.ResourcesApplication.resources<span style="color: blue;">&lt;/</span><span style="color: #a31515;">LogicalName</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">EmbeddedResource</span><span style="color: blue;">&gt;
</span></pre>
<p>Retrouvez les sources <a href="http://blog.experida.fr/wp-content/uploads/2010/11/Resources.zip">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/11/14/utilisation-dun-fichier-de-ressource-resx-avec-silverlight-4-et-les-ria-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RIA Services et autorisations</title>
		<link>http://blog.experida.fr/2010/11/06/ria-services-et-autorisations/</link>
		<comments>http://blog.experida.fr/2010/11/06/ria-services-et-autorisations/#comments</comments>
		<pubDate>Fri, 05 Nov 2010 23:20:26 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[autorisations]]></category>
		<category><![CDATA[RIA Services]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/11/06/ria-services-et-autorisations/</guid>
		<description><![CDATA[Aujourd’hui, pour le développement d&#8217;une application Silverlight utilisant les RIA Services, j&#8217;ai mis en place un module d’authentification basé sur l&#8217;authentification Forms. Par défaut, j&#8217;ai pour habitude d&#8217;interdire l&#8217;accès au site à toutes les personnes non authentifiées via quelques lignes dans le web.config. &#60;authorization&#62; &#60;deny user=&#34;?&#34; /&#62; &#60;/autorization&#62; &#160; L&#8217;application sur laquelle je travaille contient [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Aujourd’hui, pour le développement d&#8217;une application Silverlight utilisant les RIA Services, j&#8217;ai mis en place un module d’authentification basé sur l&#8217;authentification Forms.</p>
<p align="justify">Par défaut, j&#8217;ai pour habitude d&#8217;interdire l&#8217;accès au site à toutes les personnes non authentifiées via quelques lignes dans le web.config.</p>
<div align="justify">
<pre class="code">  <span style="color: blue">&lt;</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">deny </span><span style="color: red">user</span><span style="color: blue">=</span>&quot;?&quot; <span style="color: blue">/&gt;
  &lt;/</span><span style="color: #a31515">autorization</span><span style="color: blue">&gt;
</span></pre>
</div>
<p align="justify">&#160;</p>
<p><span id="more-240"></span></p>
<p align="justify">L&#8217;application sur laquelle je travaille contient un fichier xap pour le module d&#8217;authentification et un second fichier xap pour le reste de l&#8217;application.</p>
<p align="justify">Afin que le client soit capable de télécharger le xap d&#8217;authentification au lancement de l&#8217;application, il faut ajouter dans le web.config une balise location pointant vers le xap et préciser qu&#8217;on autorise tous les utilisateurs authentifiés et non authentifiés à y accéder.</p>
<div align="justify">
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">location </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">’ClientBin/Authentication.xap</span>&quot;<span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">allow </span><span style="color: red">user</span><span style="color: blue">=</span>&quot;<span style="color: blue">*</span>&quot;<span style="color: blue">/&gt;
      &lt;/</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">location</span><span style="color: blue">&gt;
</span></pre>
</div>
<p align="justify">A présent le client arrive à charger le xap et à afficher la fenêtre d&#8217;authentification.</p>
<p align="justify">Mais il reste encore un problème à régler.</p>
<p align="justify">Il existe côté serveur un DomainService contenant notamment une méthode Login. Lors de la compilation un DomainContext est créé du côté client.</p>
<p align="justify">Après que l&#8217;utilisateur ait entré ses identifiants, on appelle la méthode login du DomainService, mais le serveur retourne une erreur indiquant que le service n&#8217;a pas été trouvé.</p>
<p align="justify">Pour qu&#8217;il soit accessible, il faut au même titre que pour le xap,&#160; autoriser l&#8217;accès.</p>
<p align="justify">Derrière chaque&#160; DomainService se cache un service WCF et donc un fichier avec une extension .svc.</p>
<p align="justify">En partant du principe que votre DomainDervice se trouve dans le dossier Service de l&#8217;application web, le nom final du svc sera le suivant:</p>
<p align="justify"><a href="http://host/service/lenomdemonapplicationweb-lenomdemondomainservice.svc">http://host/service/lenomdemonapplicationweb-lenomdemondomainservice.svc</a></p>
<p align="justify">Le Framework fait la concaténation du nom de l&#8217;application web, avec le nom du DomainService, en remplaçant tous les points par des tirets. </p>
<p align="justify">Il ne vous reste plus qu’à ajouter une dernière balise Location dans le web.config afin que le DomainService soit accessible.</p>
<div align="justify">
<pre class="code">  <span style="color: blue">&lt;</span><span style="color: #a31515">location </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">service/lenomdemonapplicationweb-lenomdemondomainservice.svc</span>&quot;<span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">allow </span><span style="color: red">user</span><span style="color: blue">=</span>&quot;<span style="color: blue">*</span>&quot;<span style="color: blue">/&gt;
      &lt;/</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">system.web</span><span style="color: blue">&gt;
  &lt;/</span><span style="color: #a31515">location</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Merci à Fiddler qui permet de voir les requêtes http.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/11/06/ria-services-et-autorisations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4 / MEF: Navigation et chargement de modules &#224; la demande</title>
		<link>http://blog.experida.fr/2010/10/30/silverlight-4-navigation-et-chargement-de-modules-a-la-demande/</link>
		<comments>http://blog.experida.fr/2010/10/30/silverlight-4-navigation-et-chargement-de-modules-a-la-demande/#comments</comments>
		<pubDate>Sat, 30 Oct 2010 02:47:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[mef]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Export]]></category>
		<category><![CDATA[Import]]></category>
		<category><![CDATA[INavigationContentLoader]]></category>
		<category><![CDATA[Module]]></category>
		<category><![CDATA[OnDemand]]></category>
		<category><![CDATA[Part]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/10/30/silverlight-4-navigation-et-chargement-de-modules-a-la-demande/</guid>
		<description><![CDATA[Il y&#160; a quelques semaines, j’ai écris un billet traitant de la mise en place du pattern MVVM avec Silverlight 4 et MEF. Dans cet exemple, nous avions une application Silverlight dans laquelle on avait ajouté une page Home et une page ListePersonnes. Dans ce nouveau billet nous allons nous intéresser à deux points. Comment [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Il y&nbsp; a quelques semaines, j’ai écris un <a href="http://blog.experida.fr/2010/10/05/silverlight-4-pattern-mvvm-et-resolution-mef-e28093-partie-1" target="_blank">billet</a> traitant de la mise en place du pattern MVVM avec Silverlight 4 et MEF. Dans cet exemple, nous avions une application Silverlight dans laquelle on avait ajouté une page Home et une page ListePersonnes.</p>
<p align="justify">Dans ce nouveau billet nous allons nous intéresser à deux points.</p>
<ul>
<li>
<div align="justify">Comment faire pour charger une page à la demande </div>
<li>
<div align="justify">Comment charger un module pouvant contenir des ressources supplémentaires à la page.</div>
</li>
</ul>
<p align="justify">Pour le code, nous allons repartir de celui que j’avais précédemment ajouté et que vous pouvez récupérer <a href="http://blog.experida.fr/wp-content/uploads/2010/10/DemoSilverlightMEF.zip">ici</a></p>
<p><span id="more-239"></span>
<p align=" justify?&gt;&lt;u&gt;&lt;strong&gt;Chargement d&rsquo;une page &agrave; la demande:&lt;/strong&gt;&lt;/u&gt;&lt;/p&gt;<br />
&lt;p align=" justify?>Ouvrez le UserControl MainPage.xaml. Dans le code xaml de cette page, vous remarquerez la présence d’un élément nommé UriMapper chargé de faire le mapping entre une Uri et une page xaml.</p>
<p align="justify">En regardant d’un peu plus près pour voir comment tout cela fonctionne, on s’aperçoit que l’élément Frame via sa propriété ContentLoader met à disposition un objet chargé de fournir un contenu correspondant à l’Uri vers laquelle on navigue. Cette propriété est de type <strong>INavigationContentLoader</strong>. Dans version 4, Silverlight possède une implémentation par défaut nommée <strong>PageResourceContentLoader</strong>, permettant de réaliser le comportement vu ci-dessus, à savoir une Uri vers une page.</p>
<p align="justify">Il ne faut pas oublier que Silverlight est avant tout une technologie côté client et donc pour fonctionner correctement, l’api doit télécharger sur le client un fichier xap avec le contenu de l’application à exécuter.&nbsp; Les pages peuvent faire appel à différentes ressources ( images, dlls &#8230;..), ce qui peut très vite faire prendre du poids au fichier xap de l&#8217;application principale et donc notamment allonger le temps de chargement de l’application.</p>
<p align="justify">Une solution possible est donc de faire en sorte qu’une page soit téléchargée uniquement lorsqu’on la demande.</p>
<p align="justify">Pour y parvenir je me suis reposé sur un ContentLoader créé par <a href="http://www.davidpoll.com/" target="_blank">David Poll</a>. Bien entendu ce content loader implémente l’interface <strong>INavigationContentLoader</strong>.&nbsp; Il permet de mettre en relation une Uri et une page qui se trouve dans un fichier xap séparé du xap principal.</p>
<p align="justify">Voyons le code dont il est constitué et comment il fonctionne.</p>
<p align="justify">Nous avons un premier projet <strong>ContentLoader.Utils</strong> contenant les classes suivantes:</p>
<ul>
<li>
<div align="justify">ContentLoaderBase.cs</div>
<li>
<div align="justify">ContentLoaderBaseAsyncResult.cs</div>
<li>
<div align="justify">LoaderBase.cs</div>
</li>
</ul>
<p align="justify">Comme son nom l’indique <strong>ContentLoaderBase</strong> simplifie la mise en place d’un ContentLoader en fournissant un comportement de base, notamment au travers de l’implémentation de l’interface de <strong>INavigationContentLoader</strong>:</p>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">INavigationContentLoader
</span>{
   <span style="color: green">    </span><span style="color: #2b91af">IAsyncResult </span>BeginLoad(<span style="color: #2b91af">Uri </span>targetUri, <span style="color: #2b91af">Uri </span>currentUri,
             <span style="color: #2b91af">AsyncCallback </span>userCallback, <span style="color: blue">object </span>asyncState);
   <span style="color: green">    </span><span style="color: blue">void </span>CancelLoad(<span style="color: #2b91af">IAsyncResult </span>asyncResult);
       <span style="color: blue">bool </span>CanLoad(<span style="color: #2b91af">Uri </span>targetUri, <span style="color: #2b91af">Uri </span>currentUri);
    <span style="color: green">   </span><span style="color: #2b91af">LoadResult </span>EndLoad(<span style="color: #2b91af">IAsyncResult </span>asyncResult);
}
</pre>
<ul>
<li><strong>BeginLoad </strong>permet de démarrer le chargement d’un contenu correspondant à l’Uri de manière asynchrone.
<li><strong>CancelLoad</strong> pour annuler une opération de chargement
<li><strong>CanLoad</strong> pour indiquer si l’Uri peut être chargée
<li><strong>EndLoad</strong> pour terminer l’opération asynchrone de chargement du contenu</li>
</ul>
<p>Regardons plus en détail la méthode <strong>BeginLoad</strong></p>
<p><strong><u>Code de BeginLoad:</u></strong></p>
<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">IAsyncResult </span>BeginLoad(<span style="color: #2b91af">Uri </span>targetUri,
            <span style="color: #2b91af">Uri </span>currentUri, <span style="color: #2b91af">AsyncCallback </span>userCallback,
            <span style="color: blue">object </span>asyncState)
        {
            <span style="color: #2b91af">LoaderBase </span>loader = CreateLoaderPrivate();
            <span style="color: #2b91af">ContentLoaderBaseAsyncResult </span>result =
                <span style="color: blue">new </span><span style="color: #2b91af">ContentLoaderBaseAsyncResult</span>(asyncState,
                    loader, userCallback);
            result.BeginLoadCompleted = <span style="color: blue">false</span>;
            loader.Result = result;
            <span style="color: blue">lock </span>(result.Lock)
            {
                loader.Load(targetUri, currentUri);
                result.BeginLoadCompleted = <span style="color: blue">true</span>;
                <span style="color: blue">return </span>result;
            }
        }
</pre>
<p align="justify">Nous commençons par faire appel à la méthode CreateLoaderPrivate pour créer une instance de classe héritant de LoaderBase. En effet LoaderBase est également une classe abstraite. </p>
<div align="justify">
<pre class="code"><span style="color: blue">protected abstract </span><span style="color: #2b91af">LoaderBase </span>CreateLoader();

       <span style="color: blue">private </span><span style="color: #2b91af">LoaderBase </span>CreateLoaderPrivate()
       {
           <span style="color: #2b91af">LoaderBase </span>loader = CreateLoader();
           loader.ContentLoader = <span style="color: blue">this</span>;
           <span style="color: blue">return </span>loader;
       }
</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Le ContentLoader personnalisé devra surcharger la méthode CreateLoader pour créer un LoaderBase et le retourner au ContentLoaderBase qui se chargera alors d’appeler la méthode Load du LoaderBase pour lancer le chargement du contenu. La création d’un loader héritant de LoaderBase permet de garder la logique de chargement, d’annulation.. séparée du ContentLoader lui même.</p>
<p align="justify">Vous pourrez voir plus de code concernant cette classe dans le fichier zip joint à la&nbsp; fin du billet.</p>
<p align="justify">Dernier point que nous allons aborder par rapport à la méthode BeginLoad, le type de retour. On retourne ici un IAsyncResult qui représente le statut d’une opération asynchrone. Pour ce la David a également créé une classe nommée <strong>ContentLoaderBaseAsyncResult</strong> qui&nbsp; implémente l’interface <strong>IAsyncResult</strong>.</p>
<pre class="code"><span style="color: blue">internal class </span><span style="color: #2b91af">ContentLoaderBaseAsyncResult </span>: <span style="color: #2b91af">IAsyncResult
   </span>{
       <span style="color: blue">public </span>ContentLoaderBaseAsyncResult(<span style="color: blue">object </span>asyncState,
           <span style="color: #2b91af">LoaderBase </span>loader, <span style="color: #2b91af">AsyncCallback </span>callback)
       {
           <span style="color: blue">this</span>.AsyncState = asyncState;
           <span style="color: blue">this</span>.Loader = loader;
           <span style="color: blue">this</span>.Lock = <span style="color: blue">new object</span>();
           <span style="color: blue">this</span>.Callback = callback;
           AsyncWaitHandle = <span style="color: blue">new </span><span style="color: #2b91af">AutoResetEvent</span>(<span style="color: blue">false</span>);
       }

       <span style="color: blue">internal </span><span style="color: #2b91af">LoaderBase </span>Loader { <span style="color: blue">get</span>; <span style="color: blue">private set</span>; }
       <span style="color: blue">internal </span><span style="color: #2b91af">AsyncCallback </span>Callback { <span style="color: blue">get</span>; <span style="color: blue">private set</span>; }
       <span style="color: blue">internal </span><span style="color: #2b91af">Exception </span>Error { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
       <span style="color: blue">internal object </span>Page { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
       <span style="color: blue">internal </span><span style="color: #2b91af">Uri </span>RedirectUri { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
       <span style="color: blue">internal object </span>Lock { <span style="color: blue">get</span>; <span style="color: blue">private set</span>; }
       <span style="color: blue">internal bool </span>BeginLoadCompleted { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

       <span style="color: blue">#region </span>IAsyncResult Members

       <span style="color: blue">public object </span>AsyncState
       {
           <span style="color: blue">get</span>;
           <span style="color: blue">private set</span>;
       }

       <span style="color: blue">public </span>System.Threading.<span style="color: #2b91af">WaitHandle </span>AsyncWaitHandle
       {
           <span style="color: blue">get</span>;
           <span style="color: blue">private set</span>;
       }

       <span style="color: blue">public bool </span>CompletedSynchronously
       {
           <span style="color: blue">get</span>;
           <span style="color: blue">private set</span>;
       }

       <span style="color: blue">public bool </span>IsCompleted
       {
           <span style="color: blue">get</span>;
           <span style="color: blue">private set</span>;
       }

       <span style="color: blue">public void </span>Complete()
       {
           <span style="color: blue">this</span>.CompletedSynchronously = !BeginLoadCompleted;
           <span style="color: blue">this</span>.IsCompleted = <span style="color: blue">true</span>;
           (<span style="color: blue">this</span>.AsyncWaitHandle <span style="color: blue">as </span><span style="color: #2b91af">AutoResetEvent</span>).Set();
       }

       <span style="color: blue">#endregion
   </span>}
</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Cette implémentation de IAsyncResult contient également des propriétés supplémentaires comme Error pour savoir si une erreur a été levée durant l’opération, ou Page qui va contenir la Page présente dans le xap téléchargé à la fin de l&#8217;opération.</p>
<p align="justify">L’instance créée dans BeginLoad est passée au loader, notamment avec un paramètre <strong>userCallback </strong>qui correspond à une méthode que le ContentLoaderBase pourra appeler une fois l’opération terminée.</p>
<pre class="code"><span style="color: blue">if </span>(Dispatcher.CheckAccess())
{
    ((<span style="color: #2b91af">ContentLoaderBaseAsyncResult</span>)result).Callback(result);
}
<span style="color: blue">else
</span>{
    Dispatcher.BeginInvoke(() =&gt;
             ((<span style="color: #2b91af">ContentLoaderBaseAsyncResult</span>)result).Callback(result));
 }
</pre>
<p>Maintenant que nous avons fait une revue globale des classes nécessaires au bon fonctionnement d’un ContentLoader personnalisé, passons justement au code le concernant. Ce ContentLoader s’appuie sur MEF pour découvrir et faire la résolution des pages d’où son nom <strong>MEFContentLoader.</strong> </p>
<p>Afin d’utiliser ce ContentLoader, plusieurs modifications doivent être faites:</p>
<p>Mettre à jour l’élément navigation:Frame qui se trouve dans MainPage. </p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="ContentFrame"
                       </span><span style="color: red">Style</span><span style="color: blue">="{</span><span style="color: #a31515">StaticResource </span><span style="color: red">ContentFrameStyle</span><span style="color: blue">}"
                       </span><span style="color: red">Source</span><span style="color: blue">="/Home" </span><span style="color: red">Navigated</span><span style="color: blue">="ContentFrame_Navigated"
                       </span><span style="color: red">NavigationFailed</span><span style="color: blue">="ContentFrame_NavigationFailed"&gt;
                &lt;</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame.ContentLoader</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">MefNav</span><span style="color: blue">:</span><span style="color: #a31515">MEFContentLoader </span><span style="color: blue">/&gt;
                &lt;/</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame.ContentLoader</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame</span><span style="color: blue">&gt;
</span></pre>
<p align="justify">Comme vous l’aurez compris, en faisant cette modification dans le code xaml, on va désormais utiliser MEFContentLoader et non plus le ContentLoader par défaut.</p>
<p>Le contrôle utilisé pour faire un lien vers une page est généralement un HyperlinkButton. Dans le cas de la page Home qui restera dans le projet principale, rien ne change<span style="color: blue"> </span></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">HyperlinkButton </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="Home" </span><span style="color: red">Style</span><span style="color: blue">="{</span><span style="color: #a31515">StaticResource </span><span style="color: red">LinkStyle</span><span style="color: blue">}"
            </span><span style="color: red">NavigateUri</span><span style="color: blue">="/Home" </span><span style="color: red">TargetName</span><span style="color: blue">="ContentFrame" </span><span style="color: red">Content</span><span style="color: blue">="home"/&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Par contre pour la page ListePersonnes que nous allons mettre dans un xap / une application différente, nous précisons au niveau de l’HyperlinkButton via une propriété attachée, le nom du fichier xap&nbsp; qui contiendra la page.</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">HyperlinkButton </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">="MyPage"
               </span><span style="color: red">Style</span><span style="color: blue">="{</span><span style="color: #a31515">StaticResource </span><span style="color: red">LinkStyle</span><span style="color: blue">}"
               </span><span style="color: red">NavigateUri</span><span style="color: blue">="/MyPage"
               </span><span style="color: red">MefNav</span><span style="color: blue">:</span><span style="color: red">MEFContentLoader.Xap</span><span style="color: blue">="Personnes.xap"
               </span><span style="color: red">TargetName</span><span style="color: blue">="ContentFrame"
               </span><span style="color: red">Content</span><span style="color: blue">="MyPage"/&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>MefNav est un namespace que nous avons ajouté dans la déclaration du UserControl, pointant vers MEFContentLoader, la classe dans laquelle se trouve la propriété attachée.</p>
<pre class="code">    <span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">MefNav</span><span style="color: blue">="clr-namespace:SilverlightApp.ContentLoader.Mef
                    ;assembly=SilverlightApp.ContentLoader.Mef"
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<div align="justify">
<pre class="code"><span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>XapProperty =
    <span style="color: #2b91af">DependencyProperty</span>.RegisterAttached(<span style="color: #a31515">"Xap"</span>,
    <span style="color: blue">typeof</span>(<span style="color: blue">string</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">HyperlinkButton</span>),
    <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(<span style="color: blue">null</span>, XapPropertyChangedCallback));

<span style="color: blue">public static string </span>GetXap(<span style="color: #2b91af">DependencyObject </span>obj)
{
    <span style="color: blue">return </span>(<span style="color: blue">string</span>)obj.GetValue(XapProperty);
}

<span style="color: blue">public static void </span>SetXap(<span style="color: #2b91af">DependencyObject </span>obj, <span style="color: blue">string </span>value)
{
    obj.SetValue(XapProperty, value);
}

<span style="color: blue">public static void
    </span>XapPropertyChangedCallback(<span style="color: #2b91af">DependencyObject </span>d,
    <span style="color: #2b91af">DependencyPropertyChangedEventArgs </span>e)
{
    <span style="color: blue">var </span>button = (<span style="color: #2b91af">HyperlinkButton</span>)d;
    _uriMap[button.NavigateUri] = (<span style="color: blue">string</span>)e.NewValue;
}
<span style="color: blue"></pre>
</div>
<p></span><a href="http://11011.net/software/vspaste"></a></p>
<blockquote>
<p align="justify">&nbsp;</p>
</blockquote>
<p align="justify">La propriété attachée possède une méthode callback appelée dès que sa valeur est modifiée. </p>
<p align="justify">Elle permet de stocker dans un dictionnaire nommé _uriMap une relation entre l’Uri ou l’on navigue et le fichier xap correspondant.</p>
<p align="justify">Comme nous avons vu plus haut, le <strong>ContentLoader</strong> se base sur le Framework MEF pour découvrir les pages. Mais avant de pouvoir utiliser MEF, il faut configurer un <strong>CompositionContainer</strong> et un ou plusieurs catalogues pour permette au conteneur de savoir où aller chercher les Pages / Parts. Pour cela, la classe MefContentLoader commence par créer un Loader héritant de LoaderBase qui va appeler une méthode <strong>Initialize</strong>. Cette méthode est appelée si c&#8217;est la première fois que la méthode <strong>Load</strong> du Loader est appelée. Regardons comment le conteneur est initialisé.</p>
<pre class="code">_catalog.Catalogs.Add(<span style="color: blue">new </span><span style="color: #2b91af">DeploymentCatalog</span>());
Container = <span style="color: blue">new </span><span style="color: #2b91af">CompositionContainer</span>(_catalog);

<span style="color: #2b91af">CompositionHost</span>.Initialize(Container);
<span style="color: #2b91af">CompositionInitializer</span>.SatisfyImports(<span style="color: blue">this</span>);
_initialized = <span style="color: blue">true</span>;
</pre>
<p>Nous commençons par créer un <strong>DeploymentCatalog</strong>, sans lui passer de paramètre, ce qui signifie qu&#8217;il permettra de découvrir les différentes Parts dans le xap courant à savoir le xap principal de l&#8217;application. Ce dernier est ensuite ajouté dans un <strong>AggregateCatalog</strong> qui peut également contenir d&#8217;autres catalogues en fonction du besoin, qui lui même est passé en paramètre du conteneur créé.</p>
<p>Comme nous appelons ici la méthode Initialize de <strong>CompositionHost</strong> et qu&#8217;elle ne peut être appelée qu&#8217;une seule fois, il faut vérifier si le conteneur a déjà été initialisé, d&#8217;où l&#8217;utilisation de la variable de type boolean _<strong>initialized</strong>.</p>
<p>Notez également l&#8217;appel de la méthode <strong>SatisfyImports</strong> sur l&#8217;instance courante. Si on appelle cette méthode, cela signifie que MefContentLoader contient au moins un Import à satisfaire.</p>
<p>En effet c&#8217;est bien le cas. L&#8217;élément Import est représenté via la propriété <strong>PageFactories</strong>.</p>
<pre class="code">[<span style="color: #2b91af">ImportMany</span>(AllowRecomposition = <span style="color: blue">true</span>)]
        <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">ExportFactory</span>&lt;<span style="color: #2b91af">Page</span>, <span style="color: #2b91af">IExportPageMetadata</span>&gt;&gt;
</pre>
</p>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Que pouvons nous dire de cette propriété:</p>
<ul>
<li>nous nous attendons à avoir une collection de Parts basées sur un contrat de type Page.
<li>des métadonnées sont accessibles via l&#8217;interface <strong>IExportPageMetadata, </strong>ce qui va permettre de filtrer en fonction de l&#8217;Uri courante.
<li>l&#8217;utilisation de <strong>AllowRecomposition = true</strong>, permettra à la propriété de se mettre à jour pour éventuellement fournir de nouvelles Parts suite à l&#8217;ajout ou à la suppression d&#8217;un catalogue dans le conteneur.</li>
</ul>
<p>Comme vous le savez, avec MEF, tout est basé sur des Imports et des Exports. Passons donc aux exports.</p>
<p>Afin de ne pas avoir plusieurs attributs (export, metadata&#8230;) à créer sur les parts export, un seul attribut héritant <strong>d&#8217;ExportAttribute </strong>est ajouté.</p>
<pre class="code">[<span style="color: #2b91af">MetadataAttribute</span>]
   [<span style="color: #2b91af">AttributeUsage</span>(<span style="color: #2b91af">AttributeTargets</span>.Class,
       AllowMultiple = <span style="color: blue">false</span>,
       Inherited = <span style="color: blue">true</span>)]
   <span style="color: blue">public class </span><span style="color: #2b91af">ExportPageAttribute </span>: <span style="color: #2b91af">ExportAttribute
   </span>{
       <span style="color: blue">public string </span>NavigateUri { <span style="color: blue">get</span>; <span style="color: blue">private set</span>; }

       <span style="color: blue">public </span>ExportPageAttribute(<span style="color: blue">string </span>uri)
           : <span style="color: blue">base</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Page</span>))
       {
           <span style="color: blue">if </span>(<span style="color: blue">string</span>.IsNullOrEmpty(uri))
               <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">"uri"</span>);

           <span style="color: blue">this</span>.NavigateUri = uri;
       }
   }
</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Notez <strong>MetadataAttribute, </strong>pour préciser que l&#8217;attribut <strong>ExportPageAttribute</strong> transporte des métadonnées qui seront accessibles aux travers de l&#8217;interface <strong>IExportPageMetadata.</strong></p>
<p align="justify">Le contrat est basé sur le type Page, que l&#8217;on passe au constructeur de la classe de base.</p>
<p align="justify">Reprenons donc les deux pages ajoutées,&nbsp; Home dans l&#8217;application hôte et ListePersonnes dans une seconde application silverlight, pour générer un deuxième fichier xap.</p>
<div align="justify">
<pre class="code"> [<span style="color: #2b91af">ExportPage</span>(<span style="color: #a31515">"/Home"</span>)]
 <span style="color: blue">public partial class </span><span style="color: #2b91af">Home </span>: <span style="color: #2b91af">Page
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<div align="justify">
<pre class="code"> [<span style="color: #2b91af">ExportPage</span>(<span style="color: #a31515">"/ListePersonnes"</span>)]
 <span style="color: blue">public partial class </span><span style="color: #2b91af">ListePersonnes </span>: <span style="color: #2b91af">Page
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Que ce soit pour l&#8217;une ou pour l&#8217;autre rien ne diffère, nous avons utilisé l&#8217;attribut créé juste avant en lui passant comme métadonnée, l&#8217;Uri de navigation.</p>
<p align="justify">Ok, maintenant que les Imports et Exports sont créés que se passe il lorsqu&#8217;on navigue sur l&#8217;une des deux pages ? </p>
<p align="justify">On a vu plus haut que le MefContentLoader contenait un dictionnaire dans lequel, via la propriété attachée <strong>Xap,</strong> on avait ajouté des items dont la clé était l&#8217;Uri cible et la valeur le nom du fichier xap contenant la page à charger. </p>
<p align="justify">Dans la méthode Load, on commence par parcourir ce dictionnaire pour voir si l&#8217;on trouve un élément correspondant à l&#8217;Uri de destination. Deux cas sont alors possibles</p>
<ul>
<li>
<div align="justify">Aucun élément trouvé, ce qui signifie que soit la page n&#8217;existe pas, soit elle se trouve dans l&#8217;application hôte.</div>
<li>
<div align="justify">Un élément trouvé. On vérifie alors que le xap correspondant n&#8217;a pas déjà été téléchargé. Si le xap n&#8217;a pas encore été téléchargé</div>
<ul>
<li>
<div align="justify">on créé un <strong>DeploymentCatalog</strong> pour réaliser le téléchargement en lui passant en paramètre le nom du xap. </div>
<li>
<div align="justify">On démarre la procédure en appelant la méthode <strong>DownloadAsync</strong>. </div>
<li>
<div align="justify">Une fois le téléchargement terminé l&#8217;event <strong>DownloadCompleted</strong> du <strong>DeploymenyCatalog</strong> est appelé et on ajoute ce catalogue avec les autres catalogues créés dans la méthode Initialize. Comme la propriété Import a sa propriété <strong>AllowRecomposition</strong> à true, la Part présente dans le xap est disponible. Elle n&#8217;est pas encore instanciée, mais on peut à présent le faire.</div>
</li>
</ul>
</li>
</ul>
<pre class="code"><span style="color: blue">if </span>(_uriMap.TryGetValue(saveTargetUri, <span style="color: blue">out </span>xap)
                       &amp;&amp; xap != <span style="color: blue">null </span>&amp;&amp; !_loadedXaps.Contains(xap))
                   {
                       <span style="color: blue">var </span>dc = <span style="color: blue">new </span><span style="color: #2b91af">DeploymentCatalog</span>(xap);
                       dc.DownloadCompleted += (s, e) =&gt;
                           {
                               <span style="color: blue">if </span>(e.Error != <span style="color: blue">null</span>)
                               {
                                   <span style="color: blue">this</span>.Error(e.Error);
                                   <span style="color: blue">return</span>;
                               }

                               _catalog.Catalogs.Add(dc);
                               _loadedXaps.Add(xap);
                               NavigateToPage(targetUri);
                           };
                       dc.DownloadAsync();
                   }
</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Maintenant que les parts sont disponibles via la propriété <strong>PageFactories </strong>(sur laquelle se trouve l&#8217;attribut Import), on peut appliquer un filtre en les parcourant et en comparant les métadonnées avec l&#8217;Uri de destination, jusqu&#8217;à trouver la bonne.</p>
<pre class="code"><span style="color: blue">var </span>pageFactory = parent.PageFactories
              .SingleOrDefault((factory) =&gt; CompareUri(factory, targetUri));
</pre>
<pre class="code"><span style="color: blue">private bool
               </span>CompareUri(<span style="color: #2b91af">ExportFactory</span>&lt;<span style="color: #2b91af">Page</span>, <span style="color: #2b91af">IExportPageMetadata</span>&gt; factory,
               <span style="color: #2b91af">Uri </span>targetUri)
           {
               <span style="color: #2b91af">Uri </span>uri = GetTrimmedUri(factory.Metadata.NavigateUri);
               <span style="color: blue">if </span>(!uri.IsAbsoluteUri)
                   uri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">"dummy:///" </span>+ uri.OriginalString);
               <span style="color: blue">return </span>targetUri.Equals(uri);
           }
</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Enfin pour terminer, on instancie la propriété Value de pageFactory pour obtenir la Page. Le résultat est passé au <strong>ContentLoaderBaseAsync</strong>, via lequel on peut appeler le callback et retourner la Page.</p>
<p align="justify">Vous voilà sur la page demandée.</p>
<p align="justify">Après avoir vu, une partie du code de David Poll, nous allons voir comment faire évoluer tout ca pour charger non pas une page, mais un module complet. Un module peut notamment contenir un ViewModel dans le cas où vous appliquez le pattern MVVVM, des parts supplémentaires&#8230;</p>
<p align="justify">Dans l&#8217;exemple de David, le contrat MEF était basé sur le type Page. Dans le cas d&#8217;un module, nous allons créer une classe de base <strong>ModuleBase</strong> qui nous servira de contrat, c&#8217;est à dire<strong> Import(typeof(ModuleBase))</strong> et<strong> Export(typeof(ModuleBase)).</strong></p>
<p align="justify">Comme pour l&#8217;attribut d&#8217;export de page, nous allons créer un attribut personnalisé héritant de <strong>ExportAttribute</strong> et dans lequel nous allons spécifier qu&#8217;il peut embarquer des métadonnées. Cela nous permet notamment de simplifier l&#8217;écriture des exports.</p>
<pre class="code">[<span style="color: #2b91af">MetadataAttribute</span>]
   [<span style="color: #2b91af">AttributeUsage</span>(<span style="color: #2b91af">AttributeTargets</span>.Class,
       AllowMultiple = <span style="color: blue">false</span>, Inherited = <span style="color: blue">true</span>)]
   <span style="color: blue">public class </span><span style="color: #2b91af">ExportModuleAttribute </span>: <span style="color: #2b91af">ExportAttribute
   </span>{
       <span style="color: blue">public string </span>NavigateUri { <span style="color: blue">get</span>; <span style="color: blue">private set</span>; }
       <span style="color: blue">public </span>ExportModuleAttribute(<span style="color: blue">string </span>navigateUri)
           : <span style="color: blue">base</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">ModuleBase</span>))
       {
           <span style="color: blue">if </span>(<span style="color: blue">string</span>.IsNullOrEmpty(navigateUri))
               <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(navigateUri);

           <span style="color: blue">this</span>.NavigateUri = navigateUri;
       }
   }
</pre>
<p align="justify">Vous constaterez que nous nous appuyons toujours sur la <strong>NavigateUri</strong>. Enfin pour que côté client on puisse parcourir les métadonnées sur une base typée et non au travers d&#8217;un dictionnaire, nous ajoutons une interface <strong>IExportModuleMetadata </strong>dans laquelle on peut ajouter une partie ou la totalité des propriétés présentes dans <strong>ExportModuleAttribute</strong> selon le besoin. Ces propriétés doivent être des propriétés readonly, i.e. seulement avec un getter.</p>
<p align="justify">Comment fonctionne la classe abstraite ModuleBase?</p>
<pre class="code"><span style="color: blue">public </span>ModuleBase(<span style="color: #2b91af">CompositionContainer </span>rootContainer)
{
    <span style="color: blue">if </span>(rootContainer == <span style="color: blue">null</span>)
        <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">"rootContainer"</span>);

    <span style="color: #2b91af">AggregateCatalog </span>aggregateCatalog = <span style="color: blue">new </span><span style="color: #2b91af">AggregateCatalog</span>();

    <span style="color: #2b91af">FilteredCatalog </span>filteredCatalog =
        <span style="color: blue">new </span><span style="color: #2b91af">FilteredCatalog</span>(rootContainer.Catalog,
            p =&gt; p.Metadata
                .ContainsKey(
                <span style="color: #2b91af">CompositionConstants</span>.PartCreationPolicyMetadataName)
                &amp;&amp;
          ((<span style="color: #2b91af">CreationPolicy</span>)
          p.Metadata[<span style="color: #2b91af">CompositionConstants
            </span>.PartCreationPolicyMetadataName])
          == <span style="color: #2b91af">CreationPolicy</span>.Shared);

    <span style="color: green">//Pour permettre la découverte des parts composants l'assembly courante;
    </span><span style="color: #2b91af">AssemblyCatalog </span>assCatalog =
        <span style="color: blue">new </span><span style="color: #2b91af">AssemblyCatalog</span>(<span style="color: blue">this</span>.GetType().Assembly);

    aggregateCatalog
        .Catalogs.Add(filteredCatalog);
    aggregateCatalog
        .Catalogs.Add(assCatalog);

    ChildContainer =
        <span style="color: blue">new </span><span style="color: #2b91af">CompositionContainer</span>(aggregateCatalog, rootContainer);

    Initialize();
}
</pre>
<p align="justify">ModuleBase prend en argument de son constructeur un CompositionContainer. Ce conteneur correspond à un conteneur global. Il permet de fournir des parts qui se trouve pas dans le module mais à un niveau plus haut. </p>
<p align="justify">Comme vous pouvez le voir, nous créons un conteneur enfant. Pour la création de ce conteneur, nous nous servons de deux catalogues.</p>
<ul>
<li>
<div align="justify">Le premier, <strong>AssemblyCatalog</strong>, que l&#8217;on voit souvent permettra de découvrir les parts présentes uniquement dans le module. </div>
<li>
<div align="justify">Quant au second il s&#8217;agit d&#8217;un catalogue filtré. En effet ce catalogue permettra de découvrir toutes les parts mises à disposition par le catalogue du root container ayant pour Policy: Shared.</div>
</li>
</ul>
<p align="justify">Finalement, nous appelons la méthode Initialize qui est une méthode abstraite et qui doit par conséquent être obligatoirement surchargée par toute classe héritant de <strong>ModuleBase</strong>.</p>
<p align="justify"><strong>ModuleBase</strong> possède également une méthode <strong>GetPage</strong> qui sera appelée par le MEFContentLoader pour récupérer la page correspondant à ce module, une fois le module initialisé.</p>
<div align="justify">
<pre class="code"><span style="color: blue">protected abstract void </span>Initialize();
<span style="color: blue">public abstract </span><span style="color: #2b91af">Page </span>GetPage();
</pre>
</div>
<p align="justify">Reprenons le cas de la page ListePersonnes et adaptons le pour fonctionner dans le cadre d&#8217;un module.</p>
<p align="justify">Première chose à faire, créer une classe Module et la définir comme étant un Export <strong>ModuleBase</strong>.</p>
<div align="justify">
<pre class="code"> [<span style="color: #2b91af">ExportModule</span>(<span style="color: #a31515">"/MyPage"</span>)]
 <span style="color: blue">public class </span><span style="color: #2b91af">Module </span>: <span style="color: #2b91af">ModuleBase
</span></pre>
</div>
<p align="justify"><strong>ModuleBase</strong> a un constructeur prenant un <strong>CompositionContainer</strong>, nous devons donc lui ajouter un constructeur avec un conteneur qui ensuite va appeler le constructeur de la classe de base</p>
<pre class="code">[<span style="color: #2b91af">ImportingConstructor</span>]
       <span style="color: blue">public </span>Module([<span style="color: #2b91af">Import</span>(<span style="color: #a31515">"RootContainer"</span>)]
               <span style="color: #2b91af">CompositionContainer </span>rootContainer)
           : <span style="color: blue">base</span>(rootContainer)
       {
       }
</pre>
<p><strong>ImportingContructor </strong>permet de dire au conteneur chargé de faire la résolution de cette part, qu&#8217;il doit utiliser ce constructeur. Si on n&#8217;ajoute pas cet attribut et qu&#8217;il n&#8217;y a pas de constructeur par défaut, MEF ne saura pas quoi faire.</p>
<p>L&#8217;argument rootContainer est également une part dans notre exemple, puisqu&#8217;il possède un attribut Import avec un contrat portant sur la string &#8220;RootContainer&#8221;. Si le conteneur qui fait la résolution de ce module a bien un export avec ce contrat, le <strong>CompositionContainer</strong> sera passé au constructeur.</p>
<p>On a vu que <strong>ModuleBase</strong> avait deux méthodes abstraites.</p>
<ul>
<li>Initialize, dans laquelle nous créons et ajoutons une nouvelle part nécessaire au ViewModel de ce module. Notez l&#8217;utilisation du ChildContainer qui est créé par la classe de base et mis à disposition via une propriété.</li>
</ul>
<blockquote><pre class="code"><span style="color: blue">protected override void </span>Initialize()
{
       <span style="color: blue">var </span>ctx = <span style="color: blue">new </span><span style="color: #2b91af">PersonneDomainContext</span>();
       ChildContainer
        .ComposeExportedValue&lt;<span style="color: #2b91af">PersonneDomainContext</span>&gt;(ctx);
 }
</pre>
</blockquote>
<p><a href="http://11011.net/software/vspaste"></a></p>
<ul>
<li>GetPage, dans laquelle on demande au conteneur enfant de faire la résolution de la page.</li>
</ul>
<blockquote><pre class="code"><span style="color: blue">public override </span><span style="color: #2b91af">Page </span>GetPage()
{
           <span style="color: blue">return </span>ChildContainer
               .GetExport&lt;<span style="color: #2b91af">ListePersonnes</span>&gt;().Value;
}
</pre>
<p>Comme la page ListePersonnes contient elle aussi un Import correspondant à un ViewModel, le conteneur enfant se chargera d&#8217;en faire également la résolution et Idem pour toute part nécessaire au ViewModel.</p>
<pre class="code">[<span style="color: #2b91af">Export</span>]
   <span style="color: blue">public partial class </span><span style="color: #2b91af">ListePersonnes </span>: <span style="color: #2b91af">Page</span>,
       <span style="color: #2b91af">IPartImportsSatisfiedNotification</span>,
       <span style="color: #2b91af">IDisposable
   </span>{
      <span style="color: #2b91af">Import</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">IPersonnesViewModel</span>))]
      p<span style="color: blue">ublic </span><span style="color: #2b91af">IPersonnesViewModel </span>PersonnesViewModel { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

       <span style="color: blue">public </span>ListePersonnes()
       {
           InitializeComponent();
       }

       <span style="color: green">// Executes when the user navigates to this page.
       </span><span style="color: blue">protected override void
           </span>OnNavigatedTo(<span style="color: #2b91af">NavigationEventArgs </span>e)
       {
       }

       <span style="color: blue">public void </span>OnImportsSatisfied()
       {
           <span style="color: blue">this</span>.DataContext = PersonnesViewModel;
       }

       <span style="color: blue">public void </span>Dispose()
       {
 <span style="color: green">//Disposer les ressources créées dans cette classe
//Cette méthode sera appelée par MEF, quand la part sera détruite
       </span>}
   }
</pre>
<p><a href="http://11011.net/software/vspaste"></a></p></blockquote>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dernier point qu&#8217;il nous reste à voir avant de terminer ce billet, <strong>MefContentLoader, </strong>qui nécessite quelques changements pour supporter les modules.</p>
<p>Au même titre que nous avions une propriété <strong>PageFactories</strong>, nous allons ajouter une propriété ModuleFactories pour mettre à disposition l&#8217;ensemble des modules.</p>
<pre class="code">[<span style="color: #2b91af">ImportMany</span>(AllowRecomposition = <span style="color: blue">true</span>)]
       <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">ExportFactory</span>&lt;<span style="color: #2b91af">ModuleBase</span>, <span style="color: #2b91af">IExportModuleMetadata</span>&gt;&gt;
           ModuleFactories { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
</pre>
<p align="justify">Toute la partie téléchargement de fichier xap ne change pas.</p>
<p align="justify">Pour terminer, on filtre les modules pour trouver celui correspondant à l&#8217;Uri de navigation, puis on l&#8217;instancie si il s&#8217;agit de la première fois, ou on le récupère depuis un dictionnaire chargé de stocker les modules une fois créés. Enfin on appelle la méthode GetPage qui retourne la page et la passe au ContentLoaderBase qui va utiliser IAsyncResult pour appeler le callback et fournir le résultat.</p>
<pre class="code"><span style="color: blue">var </span>moduleFactory =
   parent.ModuleFactories
      .SingleOrDefault((factory) =&gt; CompareModuleUri(factory, targetUri));
<span style="color: blue">if </span>(moduleFactory != <span style="color: blue">null</span>)
{
   <span style="color: #2b91af">ModuleBase </span>module = <span style="color: blue">null</span>;

   <span style="color: blue">if </span>(!loadedModule.ContainsKey(targetUri))
   {
          <span style="color: blue">var </span>mod = moduleFactory.CreateExport();
           module = mod.Value;
           loadedModule.Add(targetUri, module);
   }
   <span style="color: blue">else
   </span>{
          module = loadedModule[targetUri];
   }
   Complete(module.GetPage());
}
</pre>
<p>Vous trouverez l&#8217;intégralité des sources de ce billet <a href="http://blog.experida.fr/wp-content/uploads/2010/10/SilverlightNavigationOnDemand.zip">ici</a></p>
<p><a href="http://11011.net/software/vspaste"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/10/30/silverlight-4-navigation-et-chargement-de-modules-a-la-demande/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ObservableCollection et ItemsControls</title>
		<link>http://blog.experida.fr/2010/10/16/observablecollection-et-itemscontrols/</link>
		<comments>http://blog.experida.fr/2010/10/16/observablecollection-et-itemscontrols/#comments</comments>
		<pubDate>Fri, 15 Oct 2010 22:50:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[ItemsControl]]></category>
		<category><![CDATA[ObservableCollection]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/10/16/observablecollection-et-itemscontrols/</guid>
		<description><![CDATA[En WPF ou en Silverlight, dès lors que l’on associe une collection de type ObservableCollection&#60;T&#62; à un contrôle de type ItemsControl, le simple ajout d’un item dans la collection permet de rafraichir le contrôle et de voir cet item sur l’UI. Comment gérer l’utilisation d’une ObservableCollection&#60;T&#62;, lors du développement d’un ItemsControl personnalisé. Créez un “Custom [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">En WPF ou en Silverlight, dès lors que l’on associe une collection de type ObservableCollection&lt;T&gt; à un contrôle de type ItemsControl, le simple ajout d’un item dans la collection permet de rafraichir le contrôle et de voir cet item sur l’UI.</p>
<p align="justify">Comment gérer l’utilisation d’une ObservableCollection&lt;T&gt;, lors du développement d’un ItemsControl personnalisé.</p>
<p> <span id="more-236"></span>
<p align="justify">Créez un “Custom control WPF” et faites le hériter de ItemsControl. Une fois cette étape réalisée , vous devriez pouvoir surcharger la méthode OnItemsChanged:</p>
<div align="justify">
<pre class="code"><span style="color: blue">protected override void
          </span>OnItemsChanged(<span style="color: #2b91af">NotifyCollectionChangedEventArgs </span>e)
      {
          <span style="color: blue">base</span>.OnItemsChanged(e);
      }</pre>
</div>
<p align="justify">Comme vous le remarquerez cette méthode prend en paramètre un élément de type NotifyCollectionChangedEventArgs. Ce type contient les propriétés suivantes.</p>
<p align="justify"><a href="http://blog.experida.fr/wp-content/uploads/2010/10/image3.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/10/image_thumb3.png" width="188" height="240" /></a> </p>
<p align="justify">Parmi celles-ci, une en particulier nous intéresse ici. Il s’agit de <strong>Action</strong>. En effet cette propriété permet de savoir quelle est l’action à l’origine de la modification de la collection source bindée au ItemsSource de notre ItemsControl. La propriété Action peut avoir une valeur différente pendant la durée de vie du contrôle.</p>
<ul>
<li>
<div align="justify">Add</div>
</li>
<li>
<div align="justify">Move</div>
</li>
<li>
<div align="justify">Remove</div>
</li>
<li>
<div align="justify">Replace</div>
</li>
<li>
<div align="justify">Reset</div>
</li>
</ul>
<p align="justify">A partir de là vous pouvez choisir du traitement à effectuer.</p>
<p align="justify">Prenons pour l’exemple les actions <strong>Reset</strong> et <strong>Add</strong></p>
<ul>
<li>
<div align="justify"><strong>Reset:</strong> on se trouve dans cet état, notamment lorsque l’ItemsControl est chargé pour la première fois. Pour initialiser correctement notre contrôle, nous devons donc travailler sur l’ensemble des Items disponibles via la propriété “Items” d’un ItemsControl</div>
</li>
<li>
<div align="justify"><strong>Add: </strong>on a ce niveau d’action lorsque un ou plusieurs Items sont ajoutés à la collection source. Cette fois nous souhaitons travailler seulement avec les nouveaux items. Ceux-ci sont disponibles via la propriété NewItems de NotifyCollectionChangedEventArgs.</div>
</li>
</ul>
<p align="justify">En résumant les deux cas que nous venons de voir on pourrait créer une méthode commune prenant une collection d’Items permettant de les initialiser:</p>
<pre class="code"><span style="color: blue">protected override void
    </span>OnItemsChanged(<span style="color: #2b91af">NotifyCollectionChangedEventArgs </span>e)
{
   <span style="color: blue">switch</span>(e.Action)
   {
       <span style="color: blue">case </span><span style="color: #2b91af">NotifyCollectionChangedAction</span>.Add:
           ProcessItems(e.NewItems);
           <span style="color: blue">break</span>;
       <span style="color: blue">case </span><span style="color: #2b91af">NotifyCollectionChangedAction</span>.Reset:
           ProcessItems(Items);
           <span style="color: blue">break</span>;
   }
}

<span style="color: blue">private void </span>ProcessItems(<span style="color: #2b91af">IEnumerable </span>items)
{ 

}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/10/16/observablecollection-et-itemscontrols/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF- Cr&#233;ation des ressources dans un projet s&#233;par&#233;</title>
		<link>http://blog.experida.fr/2010/10/11/wpf-creation-de28099une-assembly-pour-les-styles/</link>
		<comments>http://blog.experida.fr/2010/10/11/wpf-creation-de28099une-assembly-pour-les-styles/#comments</comments>
		<pubDate>Mon, 11 Oct 2010 20:49:56 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Blend]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[DesignTimeResource]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/10/11/wpf-creation-de28099une-assembly-pour-les-styles/</guid>
		<description><![CDATA[Lors du développement d’un contrôle, on définit des styles pour lui donner une apparence. Il n’est pas rare d’avoir besoin de ces styles dans différentes applications ou encore dans une assembly contenant des “UserControls”&#8230; Plutôt que de les redéfinir à chaque fois, nous allons voir comment les partager. Pour commencer, créons une librairie que l’on [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Lors du développement d’un contrôle, on définit des styles pour lui donner une apparence. Il n’est pas rare d’avoir besoin de ces styles dans différentes applications ou encore dans une assembly contenant des “UserControls”&#8230; Plutôt que de les redéfinir à chaque fois, nous allons voir comment les partager.</p>
<p> <span id="more-233"></span>
<p align="justify">Pour commencer, créons une librairie que l’on nommera “Styles” pour l’exemple et dans laquelle on ajoute un premier dictionnaire de ressource, “Brush.xaml”.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ResourceDictionary
    </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;

&lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Ajoutons lui un Brush par exemple pour définir le rouge par défaut à utiliser, en indiquant le code couleur ainsi qu’une “Key” pour identifier la ressource.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ResourceDictionary
    </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;
&lt;</span><span style="color: #a31515">SolidColorBrush </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Key</span><span style="color: blue">=&quot;DefaultRedColor&quot; </span><span style="color: red">Color</span><span style="color: blue">=&quot;Red&quot; /&gt;
&lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
</span></pre>
<p>Maintenant que ce brush est créé, nous souhaitons l’utiliser. Pour cela nous allons prendre deux exemples d’utilisation.</p>
<ul>
<li>1- Dans une application WPF </li>
<li>2- Dans une librairie de UserControls </li>
</ul>
<p><u>1- Application WPF</u></p>
<p align="justify">Comme vous le savez les styles peuvent être créés en tant que ressources utilisables à un niveau donné: UserControl, Application&#8230; Nous avons fait le choix de les créer dans une librairie externe et nous voulons maintenant les mettre à disposition au niveau de l’application. Pour ce faire, ouvrez le fichier App.xaml, puis référencez “Brush.xaml”</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Application.Resources</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ResourceDictionary </span><span style="color: red">Source</span><span style="color: blue">=&quot;/Styles;component/Brush.xaml&quot; /&gt;
            &lt;/</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Application.Resources</span><span style="color: blue">&gt;
</span></pre>
<p align="justify">ResourceDictionary.MergedDictionaries vous permet de spécifier un ensemble de dictionnaires, internes ou externes à&#160; l’application hôte.</p>
<p align="justify">Si maintenant vous ajoutez un élément TextBlock dans le UserControl principale avec comme Style la Ressource “DefaultRedColor”, vous devriez voir votre la font devenir rouge, dans l’éditeur comme au Runtime.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;Exemple de texte rouge&quot;
                   </span><span style="color: red">Foreground</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">StaticResource </span><span style="color: red">DefaultRedColor</span><span style="color: blue">}&quot;
                   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Center&quot;/&gt;
</span></pre>
<p>Au même titre que ce que nous venons de faire, ajoutons un deuxième dictionnaire de ressources, mais cette fois pour y définir le style par défaut de l’ensemble des boutons de l’application.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ResourceDictionary
    </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;
    &lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">x</span><span style="color: blue">:</span><span style="color: #a31515">Type </span><span style="color: red">Button</span><span style="color: blue">}&quot;&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Width&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;150&quot;/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Height&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;25&quot; /&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Content&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;This is my content&quot;/&gt;
    &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Comme vous pourrez le remarquer, l’élément style n’a pas de Key, ce qui indique que les boutons se trouvant dans le champs d’application auront ce style par défaut.</p>
<p>Comme pour “Brush.xaml”, vous avez juste à référencer Button.xaml dans le App.xaml et le tour est joué.</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">Application.Resources</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ResourceDictionary </span><span style="color: red">Source</span><span style="color: blue">=&quot;/Styles;component/Brush.xaml&quot; /&gt;
                &lt;</span><span style="color: #a31515">ResourceDictionary </span><span style="color: red">Source</span><span style="color: blue">=&quot;/Styles;component/Button.xaml&quot; /&gt;
            &lt;/</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Application.Resources</span><span style="color: blue">&gt;
</span></pre>
<p>Ajoutez un bouton et vous devriez maintenant avoir le visuel suivant dans votre éditeur:</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">StackPanel </span><span style="color: red">Orientation</span><span style="color: blue">=&quot;Vertical&quot;&gt;
        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;Exemple de texte rouge&quot;
                   </span><span style="color: red">Foreground</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">StaticResource </span><span style="color: red">DefaultRedColor</span><span style="color: blue">}&quot;
                   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Center&quot;/&gt;
        &lt;</span><span style="color: #a31515">Button </span><span style="color: red">Content</span><span style="color: blue">=&quot;Button - App2&quot; /&gt;
    &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/10/image.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/10/image_thumb.png" width="324" height="120" /></a><u> 2- Librairie de UserControls</u></p>
<p align="justify">Ajoutons dans ce projet un UserControl complètement inutile, contenant deux “Button” et un “TextBlock” en précisant comme on l’a fait dans l’application hôte un foreground pour le “TextBlock”, le texte par défaut pour le premier bouton et un texte personnalisé pour le second.</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">StackPanel </span><span style="color: red">Orientation</span><span style="color: blue">=&quot;Vertical&quot; </span><span style="color: red">Grid.Column</span><span style="color: blue">=&quot;1&quot;&gt;
        &lt;</span><span style="color: #a31515">TextBlock   </span><span style="color: red">Text</span><span style="color: blue">=&quot;Mon UserControl&quot; </span><span style="color: red">FontSize</span><span style="color: blue">=&quot;24&quot;
                   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Center&quot;
                   </span><span style="color: red">Foreground</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">StaticResource </span><span style="color: red">DefaultRedColor</span><span style="color: blue">}&quot;/&gt;
        &lt;</span><span style="color: #a31515">Button  </span><span style="color: blue">/&gt;
        &lt;</span><span style="color: #a31515">Button </span><span style="color: red">Content</span><span style="color: blue">=&quot;Button 2&quot;/&gt;
    &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Alors à juste titre, vous allez me dire: oui mais la police reste noire. </p>
<p>C’est là que la petite astuce entre en jeu.</p>
<p>Ouvrez la solution sous Blend 4, puis votre fichier xaml correspondant au UserControl. Vous devriez voir apparaître une popup comme la suivante:</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/10/image1.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://blog.experida.fr/wp-content/uploads/2010/10/image_thumb1.png" width="443" height="288" /></a> </p>
<p align="justify">Blend vous propose une liste des Dictionnaires de ressources qu’il a trouvé dans la solution. En sélectionnant par exemple “Brush.xaml”, Blend va ajouter au dossier “Properties” du projet un fichier par défaut caché sous VS2010, nommé “DesignTimeResources.xaml”. Comme son nom le laisse présager, il est maintenant possible d’éditer votre UserControls avec les Styles créés dans la librairie “Styles”.</p>
<p align="justify"><u>DesignTimeResources.xaml:</u></p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">ResourceDictionary
    </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;
    &lt;</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ResourceDictionary </span><span style="color: red">Source</span><span style="color: blue">=&quot;/Styles;component/Brush.xaml&quot;/&gt;
        &lt;</span><span style="color: #a31515">ResourceDictionary </span><span style="color: red">Source</span><span style="color: blue">=&quot;/Styles;component/Button.xaml&quot;/&gt;
    &lt;/</span><span style="color: #a31515">ResourceDictionary.MergedDictionaries</span><span style="color: blue">&gt;
    </span><span style="color: green">&lt;!-- Les entrées du dictionnaire de ressources sont définies ici. --&gt;
</span><span style="color: blue">&lt;/</span><span style="color: #a31515">ResourceDictionary</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
</p>
<p>Pour tester votre UserControl, ajoutez une référence dans l’application hôte vers le projet “UserControls”, puis insérez le UserControl.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Window </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">=&quot;SharedStyles_App2.MainWindow&quot;
        </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
        </span><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">uc</span><span style="color: blue">=&quot;clr-namespace:UserControls;assembly=UserControls&quot;
        </span><span style="color: red">Title</span><span style="color: blue">=&quot;MainWindow&quot; </span><span style="color: red">Height</span><span style="color: blue">=&quot;350&quot; </span><span style="color: red">Width</span><span style="color: blue">=&quot;525&quot;&gt;
    &lt;</span><span style="color: #a31515">StackPanel </span><span style="color: red">Orientation</span><span style="color: blue">=&quot;Vertical&quot;&gt;
        &lt;</span><span style="color: #a31515">TextBlock </span><span style="color: red">Text</span><span style="color: blue">=&quot;Exemple de texte rouge&quot;
                   </span><span style="color: red">Foreground</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">StaticResource </span><span style="color: red">DefaultRedColor</span><span style="color: blue">}&quot;
                   </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Center&quot;/&gt;
        &lt;</span><span style="color: #a31515">Button </span><span style="color: red">Content</span><span style="color: blue">=&quot;Button - App2&quot; /&gt;
        &lt;</span><span style="color: #a31515">uc</span><span style="color: blue">:</span><span style="color: #a31515">MyUserControl </span><span style="color: blue">/&gt;
    &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">Window</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/10/image2.png"><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" src="http://blog.experida.fr/wp-content/uploads/2010/10/image_thumb2.png" width="268" height="201" /></a> </p>
<p>Téléchargez les sources <a href="http://blog.experida.fr/wp-content/uploads/2010/10/SharedStyles-App.zip" target="_blank">ici</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/10/11/wpf-creation-de28099une-assembly-pour-les-styles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4, pattern MVVM et r&#233;solution MEF</title>
		<link>http://blog.experida.fr/2010/10/05/silverlight-4-pattern-mvvm-et-resolution-mef-e28093-partie-1/</link>
		<comments>http://blog.experida.fr/2010/10/05/silverlight-4-pattern-mvvm-et-resolution-mef-e28093-partie-1/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 23:33:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[mef]]></category>
		<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Composition]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Silverlight 4]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/10/05/silverlight-4-pattern-mvvm-et-resolution-mef-e28093-partie-1/</guid>
		<description><![CDATA[Dans ce billet, je vous propose de voir une solution pour la mise en place du pattern MVVM dans le cas d’une application Silverlight 4 utilisant la navigation par page. La résolution des éléments Views / ViewModels sera faite via le Framework MEF. Dans cette première partie, nous resterons simple à savoir pas de xap [...]]]></description>
			<content:encoded><![CDATA[<p>Dans ce billet, je vous propose de voir une solution pour la mise en place du pattern MVVM dans le cas d’une application Silverlight 4 utilisant la navigation par page. La résolution des éléments Views / ViewModels sera faite via le Framework MEF.</p>
<p>Dans cette première partie, nous resterons simple à savoir pas de xap chargés à la demande&#8230;, juste deux pages:</p>
<ul>
<li>
<div>La première affichera “Runtime Home View” si l’application est en cours d’exécution ou “DesignTime Home View” si nous sommes dans l’éditeur VS 2010 ou sous Blend.</div>
</li>
<li>
<div>La seconde listera des entités “Personne” avec un Id, un Nom et un Prénom, via un DataGrid.</div>
</li>
</ul>
<p>A noter également, que pour l’exemple, nous partirons du principe que l’application silverlight est capable de récupérer la liste des Personnes via les RIA Services. Nous ne verrons pas la partie serveur ici, cela serait hors sujet.</p>
<p>C’est parti !!</p>
<p><span id="more-223"></span></p>
<p>Dans le projet Silverlight, vous devriez avoir un dossier “Views”. Ajoutez-y deux pages silverlight. Nommez la première Home.xaml et la seconde ListePersonnes.xaml. Pour vérifier qu’il s’agit bien d’une Page, vous pouvez regarder dans le code-behind que nos deux contrôles héritent bien de Page.</p>
<p>Normalement, vous devriez avoir également un UserControl déjà créé avec pour nom “MainPage.xaml”. Dans le code xaml de ce fichier vous trouverez l’élément Navigation:Frame, ainsi que l’UriMapper qui avec son IContentLoader par défaut permet de faire correspondre une Uri à une page xaml.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">navigation</span><span style="color: blue;">:</span><span style="color: #a31515;">Frame </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="ContentFrame"
       </span><span style="color: red;">Style</span><span style="color: blue;">="{</span><span style="color: #a31515;">StaticResource </span><span style="color: red;">ContentFrameStyle</span><span style="color: blue;">}"
       </span><span style="color: red;">Source</span><span style="color: blue;">="/Home"
       </span><span style="color: red;">Navigated</span><span style="color: blue;">="ContentFrame_Navigated"
       </span><span style="color: red;">NavigationFailed</span><span style="color: blue;">="ContentFrame_NavigationFailed"&gt;
 &lt;</span><span style="color: #a31515;">navigation</span><span style="color: blue;">:</span><span style="color: #a31515;">Frame.UriMapper</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">uriMapper</span><span style="color: blue;">:</span><span style="color: #a31515;">UriMapper</span><span style="color: blue;">&gt;
   &lt;</span><span style="color: #a31515;">uriMapper</span><span style="color: blue;">:</span><span style="color: #a31515;">UriMapping </span><span style="color: red;">Uri</span><span style="color: blue;">="" </span><span style="color: red;">MappedUri</span><span style="color: blue;">="/Views/Home.xaml"/&gt;
   &lt;</span><span style="color: #a31515;">uriMapper</span><span style="color: blue;">:</span><span style="color: #a31515;">UriMapping </span><span style="color: red;">Uri</span><span style="color: blue;">="/{pageName}" </span><span style="color: red;">MappedUri</span><span style="color: blue;">="/Views/{pageName}.xaml"/&gt;
  &lt;/</span><span style="color: #a31515;">uriMapper</span><span style="color: blue;">:</span><span style="color: #a31515;">UriMapper</span><span style="color: blue;">&gt;
 &lt;/</span><span style="color: #a31515;">navigation</span><span style="color: blue;">:</span><span style="color: #a31515;">Frame.UriMapper</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">navigation</span><span style="color: blue;">:</span><span style="color: #a31515;">Frame</span><span style="color: blue;">&gt;
</span></pre>
<p>Comme vous pouvez le voir, au lancement de l’application nous pointerons vers la page Home. Nous naviguerons également vers cette page, si aucune Uri n’est précisée. Pour toutes les autres Uri, on part du principe qu’elles se trouvent là où l’on vient de les créer, à savoir dans le dossier Views.</p>
<p>Toujours dans l’application Silverlight, ajoutez un autre répertoire que l’on va appeler ViewModel, puis ajoutez-y simplement deux classes que l’on nommera HomeViewModel et ListePersonnesViewModel. Comme dans tous nos projets utilisant un ViewModel, nous allons nous appuyer sur une classe de base “ViewModelBase*”, pour pouvoir notifier l’UI lors de la modification d’une propriété du ViewModel.</p>
<p>*ViewModelBase sera présente dans les sources.</p>
<div>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">HomeViewModel </span>: <span style="color: #2b91af;">ViewModelBase
</span>{
    <span style="color: blue;">public </span>HomeViewModel()
    {

    }
}</pre>
</div>
<p>Avant de modifier le contenu de HomeViewModel et de ListePersonnesViewModel, nous allons également ajouter un contrat via une interface à ces deux ViewModels.</p>
<p><span style="text-decoration: underline;">L’interface va nous permettre :</span></p>
<ul>
<li>
<div>de créer deux implémentations de chaque ViewModel. Une fonctionnant au runtime et la seconde au designtime.</div>
</li>
<li>
<div>de définir nos ViewModels en tant  qu’export. Avec MEF, un élément ayant un attribut Export est une Part fournissant un service. Nous verrons un peu plus loin, comment consommer ce service et faire la résolution du ViewModel en question.</div>
</li>
</ul>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IHomeViewModel</span>))]
<span style="color: blue;">public class </span><span style="color: #2b91af;">HomeViewModel</span>: <span style="color: #2b91af;">ViewModelBase</span>, <span style="color: #2b91af;">IHomeViewModel</span><span style="color: #2b91af;">
</span></pre>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IPersonnesViewModel</span>))]
<span style="color: blue;">public class </span><span style="color: #2b91af;">PersonnesViewModel </span>: <span style="color: #2b91af;">ViewModelBase</span>, <span style="color: #2b91af;">IPersonnesViewModel</span><span style="color: #2b91af;">
</span></pre>
<p>Dans le code de nos interfaces, nous allons ajouter les propriétés et méthodes qu’on aura en commun dans les deux ViewModels.</p>
<p><span style="text-decoration: underline;">Par exemple pour IPersonnesViewModel on a:</span></p>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IPersonnesViewModel
    </span>{
        <span style="color: blue;">void </span>LoadData();
        <span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">Personne</span>&gt; Personnes { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
    }</pre>
<p>Pour les ViewModels utilisés lors du DesignTime, préfixez vos ViewModels par Design pour faciliter la compréhension.</p>
<p>Le Framework MEF contient une interface <strong>IPartImportsSatisfiedNotification </strong>avec une méthode <strong>OnImportsSatisfied</strong> appelée dès que tous les Imports de la Part qui l’implémente sont satisfaites. Il peut s’agir d’un Import lié à une propriété ou encore d’un service injecté via le constructeur avec l’attribut <strong>ImportingConstructor</strong>.</p>
<p>De manière à ce que nos ViewModels puissent faire appel à tout service une fois l’importation terminée, nous allons donc les faire implémenter cette interface.</p>
<p><strong><span style="text-decoration: underline;">HomeViewModel:</span></strong></p>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IHomeViewModel</span>))]
    <span style="color: blue;">public class </span><span style="color: #2b91af;">HomeViewModel</span>: <span style="color: #2b91af;">ViewModelBase</span>, <span style="color: #2b91af;">IHomeViewModel</span>,
        <span style="color: #2b91af;">IPartImportsSatisfiedNotification
    </span>{
        <span style="color: blue;">public </span>HomeViewModel()
        {
        }

        <span style="color: blue;">public void </span>OnImportsSatisfied()
        {
            LoadData();
        }

        <span style="color: blue;">public void </span>LoadData()
        {
            Message = <span style="color: #a31515;">"Runtime Home View"</span>;
        }

        <span style="color: blue;">private string </span>message;
        <span style="color: blue;">public string </span>Message
        {
            <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>message; }
            <span style="color: blue;">set
            </span>{
                message = <span style="color: blue;">value</span>;
                RaisePropertyChanged(() =&gt; Message);
            }
        }
    }</pre>
<p><strong><span style="text-decoration: underline;">PersonnesViewModel:</span></strong></p>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IPersonnesViewModel</span>))]
   <span style="color: blue;">public class </span><span style="color: #2b91af;">PersonnesViewModel </span>: <span style="color: #2b91af;">ViewModelBase</span>, <span style="color: #2b91af;">IPersonnesViewModel</span>,
       <span style="color: #2b91af;">IPartImportsSatisfiedNotification
   </span>{
       <span style="color: blue;">private readonly </span><span style="color: #2b91af;">PersonneDomainContext </span>ctx;

       <span style="color: green;">//Dependency Injection
       </span>[<span style="color: #2b91af;">ImportingConstructor</span>]
       <span style="color: blue;">public </span>PersonnesViewModel(<span style="color: #2b91af;">PersonneDomainContext </span>ctx)
       {
           <span style="color: blue;">if </span>(ctx == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"ctx"</span>);

           <span style="color: blue;">this</span>.ctx = ctx;
           Personnes = <span style="color: blue;">new </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">Personne</span>&gt;();
       }

       <span style="color: blue;">public void </span>OnImportsSatisfied()
       {
           LoadData();
       }

       <span style="color: blue;">public void </span>LoadData()
       {
           ctx.Load(ctx.GetPersonnesQuery(), (op) =&gt;
               {

                   <span style="color: blue;">if </span>(op.Error == <span style="color: blue;">null</span>)
                   {
                       <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>p <span style="color: blue;">in </span>op.Entities)
                           personnes.Add(p);

                   }
               }, <span style="color: blue;">false</span>);
       }

       <span style="color: blue;">private </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">Personne</span>&gt; personnes;
       <span style="color: blue;">public </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">Personne</span>&gt; Personnes
       {
           <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>personnes; }
           <span style="color: blue;">set
           </span>{
               personnes = <span style="color: blue;">value</span>;
               RaisePropertyChanged(() =&gt; Personnes);
           }
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Vous remarquerez que dans le cas de PersonnesViewModel, on fait appel au DomainContext PersonneDomainContext injecté via le constructeur pour récupérer les données à fournir à la vue.</p>
<p>Comme nous venons de le faire avec les ViewModels, nous allons ouvrir le code-behind de nos Vues Home.xaml et ListePersonnes.xaml et leur faire implémenter également l’interface <strong>IPartImportSatisfiedNotification</strong>.</p>
<p>Comme nous souhaitons associer à chacune de ces vues, un ViewModel pour qu’elles aient des données à afficher. Nous allons donc ajouter un Import basé sur <strong>IHomeViewModel</strong> dans Home.xaml.cs et un Import basé sur <strong>IPersonnesViewModel </strong>dans ListePersonnes.xaml.cs. Une fois ceux-ci satisfaits, la méthode OnImportSatisfied sera appelée et l’association avec le DataContext pourra se faire.</p>
<p>Comment demander à MEF de satisfaire tous ces imports que nous venons de voir.</p>
<p>Avec silverlight 4, la demande de chargement d’une page est faite par le ContentLoader par défaut, <strong>PageResourceContentLoader</strong> qui fait le mapping entre une Uri et une page.</p>
<p>De manière à satisfaire les Imports, nous allons utiliser dans ce premier billet la classe CompositionInitializer et sa méthode SatisfyImports au niveau du constructeur de nos pages.</p>
<pre class="code"><span style="color: blue;">public partial class </span><span style="color: #2b91af;">Home </span>: <span style="color: #2b91af;">Page</span>,
       <span style="color: #2b91af;">IPartImportsSatisfiedNotification
   </span>{
       [<span style="color: #2b91af;">Import</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IHomeViewModel</span>))]
       <span style="color: blue;">public </span><span style="color: #2b91af;">IHomeViewModel </span>HomeViewModel { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

       <span style="color: blue;">public </span>Home()
       {
           InitializeComponent();

           <span style="color: #2b91af;">CompositionInitializer</span>.SatisfyImports(<span style="color: blue;">this</span>);

       }

       <span style="color: green;">// Executes when the user navigates to this page.
       </span><span style="color: blue;">protected override void </span>OnNavigatedTo(<span style="color: #2b91af;">NavigationEventArgs </span>e)
       {
       }

       <span style="color: blue;">public void </span>OnImportsSatisfied()
       {
           <span style="color: blue;">this</span>.DataContext = HomeViewModel;
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;">Attention cependant il y a quelques contraintes:</span></p>
<ul>
<li>
<div>CompositionInitializer utilise par défaut un conteneur qu’il créé lui même et seuls les assemblages présents dans le xap courant seront découverts</div>
</li>
<li>
<div>Toutes les Parts créées via CompositionInitializer sont gardées jusqu’à ce que l’application soit fermée.</div>
</li>
<li>
<div>Vous ne pouvez pas appliquer la méthode SatisfyImports sur des Parts utilisant l’attribut ExportAttribute.</div>
</li>
</ul>
<p>On peut déjà palier au premier problème en combinant l’utilisation du CompositionInitializer avec la classe CompositionHost et sa méthode SatisfyImports et ainsi avoir le contrôle total sur MEF.</p>
<p>Pour cela nous allons ajouter quelques lignes de code dans le handler Application_Startup du fichier App.xaml.cs.</p>
<pre class="code"><span style="color: #2b91af;">AggregateCatalog </span>catalog = <span style="color: blue;">new </span><span style="color: #2b91af;">AggregateCatalog</span>();
catalog.Catalogs.Add(<span style="color: blue;">new </span><span style="color: #2b91af;">DeploymentCatalog</span>());
container = <span style="color: blue;">new </span><span style="color: #2b91af;">CompositionContainer</span>(catalog);
<span style="color: #2b91af;">CompositionHost</span>.Initialize(container);
<span style="color: #2b91af;">CompositionInitializer</span>.SatisfyImports(<span style="color: blue;">this</span>);</pre>
<pre class="code"><span style="color: #2b91af;">Application</span>.Current.RootVisual = MainPage;</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Ici nous créons notre propre conteneur et nous lui passons en paramètre un catalogue de type AggregateCatalog. Ce type de catalogue peut contenir des catalogues différents dont le DeploymentCatalog utilisé dans notre exemple avec son constructeur par défaut pour indiquer que MEF peut découvrir les parts du xap courant.</p>
<p>Ensuite, nous appelons la méthode Initialize de CompositionHost en lui passant le conteneur tout juste créé. Comme cette méthode ne peut être appelée qu’une seule fois, il est préférable de l’utiliser dans l’application hôte comme nous venons de le faire ici.</p>
<p>Dernier point à voir, l’édition des vues. L’utilisation des éditeurs VS ou Blend n’est pas incompatible avec la mise en place du pattern MVVM. Pour cela nous avions créés des ViewModels pouvant être utilisés au moment du design.</p>
<p>Pour les utiliser vous avez juste à initialiser le DataContext  spécifique au mode design et le tour est joué.</p>
<pre class="code"><span style="color: red;">d</span><span style="color: blue;">:</span><span style="color: red;">DataContext</span><span style="color: blue;">="{</span><span style="color: #a31515;">d</span><span style="color: blue;">:</span><span style="color: #a31515;">DesignInstance </span><span style="color: red;">local</span><span style="color: blue;">:</span><span style="color: red;">DesignPersonnesViewModel</span><span style="color: blue;">,
                </span><span style="color: red;">IsDesignTimeCreatable</span><span style="color: blue;">=True}"
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans le prochain billet, nous verrons comment adapter ce code dans une situation on l’on voudrait que chaque page soit stockée dans un fichier xap différent téléchargé à la demande.</p>
<p>Vous pouvez télécharger l’exemple complet <a href="http://blog.experida.fr/wp-content/uploads/2010/10/DemoSilverlightMEF.zip" target="_blank">ici</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/10/05/silverlight-4-pattern-mvvm-et-resolution-mef-e28093-partie-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>RIA Services Insert / Update / Delete</title>
		<link>http://blog.experida.fr/2010/09/27/ria-services-insert-update-delete/</link>
		<comments>http://blog.experida.fr/2010/09/27/ria-services-insert-update-delete/#comments</comments>
		<pubDate>Mon, 27 Sep 2010 21:21:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Delete]]></category>
		<category><![CDATA[Insert]]></category>
		<category><![CDATA[RIA Services]]></category>
		<category><![CDATA[Silverlight 4]]></category>
		<category><![CDATA[SubmitChanged]]></category>
		<category><![CDATA[Update]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/09/27/ria-services-insert-update-delete/</guid>
		<description><![CDATA[Lorsque l&#8217;on développe une application silverlight, utilisant les RIA Services, j&#8217;ai remarqué qu&#8217;une question revenait souvent, concernant l&#8217;appel des méthodes Insert / Update et Delete. Faisons donc un point, sur comment doivent être ajoutées ces méthodes et comment les utiliser.   Lors de la création de votre DomainService, celui-ci peut être généré automatiquement notamment si [...]]]></description>
			<content:encoded><![CDATA[<p>Lorsque l&#8217;on développe une application silverlight, utilisant les RIA Services, j&#8217;ai remarqué qu&#8217;une question revenait souvent, concernant l&#8217;appel des méthodes Insert / Update et Delete. Faisons donc un point, sur comment doivent être ajoutées ces méthodes et comment les utiliser.</p>
<p> <span id="more-220"></span></p>
<p>Lors de la création de votre DomainService, celui-ci peut être généré automatiquement notamment si votre model s&#8217;appuie sur EntityFramework.</p>
<p>Une fois la génération faite, si vous ouvrez le DomainService où se trouve le code , vous remarquerez que le nom des méthodes suit une règle à savoir: le nom de l&#8217;action, puis le nom de l&#8217;entité concernée.</p>
<p>En admettant que vous développez un DomainService pour la gestion des Clients, vous aurez les méthodes suivantes:</p>
<ul>
<li>
<div>InsertClient(Client client)</div>
</li>
<li>
<div>UpdateClient(Client client)</div>
</li>
<li>
<div>DeleteClient(Client client)</div>
</li>
</ul>
<p>Bien que cette règle ne soit pas compliquée à retenir, vous pouvez choisir de nommer vos méthodes comme vous le souhaitez et utiliser un des attributs suivants:</p>
<ul>
<li>
<div>[delete]</div>
</li>
<li>
<div>[insert]</div>
</li>
<li>
<div>[update]</div>
</li>
</ul>
<p>Si vous compilez votre application maintenant, vous aurez côté client un fichier auto généré contenant le DomainContext chargé de communiquer avec le DomainService coté serveur. Mais attention petite surprise, ce fichier ne contient pas les méthodes Insert / Update et Delete Client. Vous n’avez donc pas la possibilité de les appeler directement depuis le code client.</p>
<p>Comment procéder ?</p>
<p>Les RiaServices utilisent un système pour traquer les changements. Dès lors, il ne vous reste plus qu’à utiliser les méthodes Add / Remove ou à modifier tout simplement les propriétés de votre objet, pour enfin appeler la méthode SubmitChanges qui se chargera d’appeler la méthode adéquate coté serveur.</p>
<p><strong><span style="text-decoration: underline;">Ex d’insertion:</span></strong> MonDomainContext.Clients.Add(new Client {&#8230;.});</p>
<p><span style="text-decoration: underline;"><strong>Ex de suppression:</strong></span> MonDomainContext.Clients.Remove(client);</p>
<p><strong><span style="text-decoration: underline;">Ex de modification:</span></strong> client.Prenom = “Alexandre”</p>
<p><span style="text-decoration: underline;"><strong>Ex de sauvegarde:</strong></span> MonDomainContext.SubmitChanges(&#8230;.);</p>
<p>Dans votre DomainService, vous pouvez toujours ajouter les méthodes que vous souhaitez sans les attributs cités ci-dessus afin de les appeler directement côté client, mais vous  si vous tentez de faire un SubmitChanges après un Add ou un Remove, vous obtiendrez une exception vous disant que cette entité ne gère pas l’opération.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/09/27/ria-services-insert-update-delete/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF / DataTrigger et RelativeSource</title>
		<link>http://blog.experida.fr/2010/09/18/wpf-datatrigger-et-relativesource/</link>
		<comments>http://blog.experida.fr/2010/09/18/wpf-datatrigger-et-relativesource/#comments</comments>
		<pubDate>Sat, 18 Sep 2010 13:28:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[DataTrigger]]></category>
		<category><![CDATA[Self]]></category>
		<category><![CDATA[TemplatedParent]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/09/18/wpf-datatrigger-et-relativesource/</guid>
		<description><![CDATA[En WPF, comme en Silverlight, un contrôle est composé d’une partie graphique et d’une partie logique définissant son comportement. Le fichier generic.xaml qui accompagne le fichier de code MonControle.cs contient le Template par défaut du contrôle. Nous avons la possibilité de redéfinir ce Template par défaut. Imaginons que nous souhaitions modifier le Template d’un bouton [...]]]></description>
			<content:encoded><![CDATA[<p>En WPF, comme en Silverlight, un contrôle est composé d’une partie graphique et d’une partie logique définissant son comportement. Le fichier generic.xaml qui accompagne le fichier de code MonControle.cs contient le Template par défaut du contrôle.</p>
<p><span id="more-218"></span></p>
<p>Nous avons la possibilité de redéfinir ce Template par défaut. Imaginons que nous souhaitions modifier le Template d’un bouton et lui ajouter un border. Ce border doit avoir un background bleu quand il contient le mot garçon et un background rouge quand il s’agit d’une fille. Oui je sais l’exemple est très simple, mais c’est juste pour mettre en avant notre DataTrigger.</p>
<p>La première fois que j’ai créé le Template correspondant à ce scénario, je l’ai écris comme le code suivant:</p>
<div>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">ControlTemplate </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="MyButtonTemplate" </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">Button</span><span style="color: blue;">}"&gt;
 &lt;</span><span style="color: #a31515;">Border
    </span><span style="color: red;">Name</span><span style="color: blue;">="Border"
    </span><span style="color: red;">CornerRadius</span><span style="color: blue;">="5" </span><span style="color: red;">Background</span><span style="color: blue;">="LightBlue"
    </span><span style="color: red;">Width</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Width</span><span style="color: blue;">}"
    </span><span style="color: red;">Height</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Height</span><span style="color: blue;">}"&gt;
 &lt;</span><span style="color: #a31515;">ContentPresenter </span><span style="color: red;">HorizontalAlignment</span><span style="color: blue;">="Center" </span><span style="color: red;">VerticalAlignment</span><span style="color: blue;">="Center"/&gt;
 &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
 &lt;</span><span style="color: #a31515;">ControlTemplate.Triggers</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">DataTrigger </span><span style="color: red;">Binding</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Path</span><span style="color: blue;">=Content,
       </span><span style="color: red;">RelativeSource</span><span style="color: blue;">={</span><span style="color: #a31515;">RelativeSource </span><span style="color: red;">Mode</span><span style="color: blue;">=TemplatedParent}}" </span><span style="color: red;">Value</span><span style="color: blue;">="fille”&gt;
   &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">TargetName</span><span style="color: blue;">="Border" </span><span style="color: red;">Property</span><span style="color: blue;">="Background" </span><span style="color: red;">Value</span><span style="color: blue;">="Red"/&gt;
  &lt;/</span><span style="color: #a31515;">DataTrigger</span><span style="color: blue;">&gt;
 &lt;/</span><span style="color: #a31515;">ControlTemplate.Triggers</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">ControlTemplate</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p>La partie qui nous intéresse dans le code, c’est le DataTrigger.</p>
<p>L’élément DataTrigger se trouvant, dans le ControlTemplate, je pensais pouvoir utiliser comme RelativeSource Mode, TemplatedParent. Après l’ajout de deux boutons et l’exécution de l’application, vous remarquerez par vous même que cela ne fonctionne pas.</p>
<p>En réalité pour que cela puisse fonctionner, il vous faudra passer par un autre Mode de RelativeSource, le RelativeSource = Self. TemplatedParent est seulement utilisable dans la section principale, mais pas dans la section triggers.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">ControlTemplate.Triggers</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">DataTrigger </span><span style="color: red;">Binding</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Path</span><span style="color: blue;">=Content,
     </span><span style="color: red;">RelativeSource</span><span style="color: blue;">={</span><span style="color: #a31515;">RelativeSource </span><span style="color: red;">Mode</span><span style="color: blue;">=Self}}" </span><span style="color: red;">Value</span><span style="color: blue;">="fille"&gt;
   &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">TargetName</span><span style="color: blue;">="Border" </span><span style="color: red;">Property</span><span style="color: blue;">="Background" </span><span style="color: red;">Value</span><span style="color: blue;">="Red"/&gt;
  &lt;/</span><span style="color: #a31515;">DataTrigger</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">ControlTemplate.Triggers</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/09/image4.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/09/image_thumb4.png" border="0" alt="image" width="302" height="201" /></a></p>
<p>Le code est disponible <a href="http://blog.experida.fr/wp-content/uploads/2010/09/WPFDatatrigger.zip" target="_blank">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/09/18/wpf-datatrigger-et-relativesource/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ViewModel Locator / Resolver et &#8220;Blendabilit&#233;&#8221;</title>
		<link>http://blog.experida.fr/2010/09/12/viewmodel-locator-resolver-et-e2809cblendabilitee2809d/</link>
		<comments>http://blog.experida.fr/2010/09/12/viewmodel-locator-resolver-et-e2809cblendabilitee2809d/#comments</comments>
		<pubDate>Sun, 12 Sep 2010 21:49:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Blend]]></category>
		<category><![CDATA[mef]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[MEF;MVVM;Design;ViewModel Locator]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/09/12/viewmodel-locator-resolver-et-e2809cblendabilitee2809d/</guid>
		<description><![CDATA[Aujourd’hui lorsqu’on parcours les différents blogs parlant du pattern MVVM, on s’aperçoit rapidement qu’il en existe plusieurs implémentations, faites la plupart du temps  en fonction des besoins de chacun.  L’implémentation que je vais présenter dans ce billet n’a rien de nouvelle, elle s’appuie sur un ensemble de pratiques que j’ai pu noter au travers de [...]]]></description>
			<content:encoded><![CDATA[<p>Aujourd’hui lorsqu’on parcours les différents blogs parlant du pattern MVVM, on s’aperçoit rapidement qu’il en existe plusieurs implémentations, faites la plupart du temps  en fonction des besoins de chacun.  L’implémentation que je vais présenter dans ce billet n’a rien de nouvelle, elle s’appuie sur un ensemble de pratiques que j’ai pu noter au travers de différents sites de bloggeurs ( <a href="http://johnpapa.net/" target="_blank">John Papa</a>, <a href="http://blogs.msdn.com/b/gblock/" target="_blank">Glenn Block</a> &#8230;). Le but étant de les rassembler dans ce billet.</p>
<p> <span id="more-213"></span></p>
<p>Lorsqu’on parle de résolution du couple View / ViewModel, on pense de suite à deux approches: ViewModel First et View First.</p>
<p>Pour continuer à utiliser l’ensemble des fonctionnalités de Blend 4 ou du designer VS 2010, il faut nous tourner vers la seconde approche. Nous aurons donc la vue créée dans un premier temps, puis le ViewModel.</p>
<p>Pour  y parvenir la plus simple manière est d’ajouter le ViewModel en tant que Static Ressource dans le code XAML. En faisant ainsi, vous aurez une application fonctionnelle.</p>
<p>Cependant, on peut faire plusieurs reproches avec ce modèle.</p>
<ul>
<li>
<div>La View et le ViewModel sont fortement liés</div>
</li>
<li>
<div>Vous ne pouvez pas injecter de service via le constructeur du ViewModel.</div>
</li>
<li>
<div>Vos données ne sont pas spécifiques au mode design et vous devez utiliser celles qu’apporte le ViewModel via un service quelconque avec les contraintes existantes, comme par exemple un service non disponible.</div>
</li>
</ul>
<p>Pour contourner ces problèmes, une solution possible est de passer par un ViewModel Locator et de faire appel à un conteneur comme Unity ou MEF pour faire la résolution de notre ViewModel. </p>
<p>Il  existe également une seconde approche que j’ai pu voir sur le Blog de <a href="http://wildermuth.com/2009/12/27/Architecting_SL4_Applications_with_RIA_Services_MEF_and_MVVM_-_Part_3 " target="_blank">Shawn Wildermuth</a>, dans laquelle il utilise MEF dans le code behind de sa vue. La seule contrainte que je vois ici est le fait qu’il utilise MEF, mais sans donner la possibilité de changer facilement de conteneur</p>
<p>Mais revenons  à la première solution, le ViewModel Locator. Son but est de faire la résolution de nos ViewModels. Afin qu’il soit le plus générique possible, nous allons faire en sorte que le ViewModel Locator, puisse utiliser potentiellement un resolver quelconque. Dans ce billet il est représenté par son interface IViewModelResolver. Elle possède une méthode Resolv prenant en paramètre un nom de ViewModel pour la résolution et retourne un ViewModelBase dont tous les ViewModels de ce projet héritent.</p>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IViewModelResolver
   </span>{
       <span style="color: #2b91af;">ViewModelBase </span>Resolve(<span style="color: blue;">string </span>viewModelName);
   }</pre>
<p>Afin de préciser au locator le ViewModel que l’on souhaite associer à la vue, nous allons également nous appuyer sur une propriété indexée qui prendra en paramètre le nom du ViewModel à résoudre.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">ViewModelLocator
    </span>{
        <span style="color: blue;">public </span>ViewModelLocator()
        {
        }

        <span style="color: blue;">public </span><span style="color: #2b91af;">IViewModelResolver </span>Resolver { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

        <span style="color: blue;">public object this</span>[<span style="color: blue;">string </span>viewModelName]
        {
            <span style="color: blue;">get
            </span>{
                <span style="color: blue;">return </span>Resolver.Resolve(viewModelName);
            }
        }
    }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Le ViewModel Locator étant terminé, passons au développement d’un resolver et plus particulièrement ici d’un MEFResolver. Comme vu ci-dessous notre resolver doit implémenter l’interface IViewModelResolver qui contient je le rappelle une méthode Resolv.</p>
<pre class="code"> <span style="color: blue;">public class </span><span style="color: #2b91af;">MEFResolver </span>: <span style="color: #2b91af;">IViewModelResolver
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans la solution jointe à ce billet, vous pourrez voir dans les propriétés du projet MVVMTemplate.ViewModel qu’une fois la compilation terminée, la dll est copiée dans un répertoire nommé MVVM_Bin. Pour cela, notre MEFResolver va créer un DirectoryCatalog pointant sur ce répertoire. </p>
<pre class="code"><span style="color: blue;">var </span>catalog = <span style="color: blue;">new </span><span style="color: #2b91af;">AggregateCatalog</span>();
           catalog.Catalogs.Add(<span style="color: blue;">new </span><span style="color: #2b91af;">DirectoryCatalog</span>(DirectoryPath));
           <span style="color: blue;">var </span>mefContainer = <span style="color: blue;">new </span><span style="color: #2b91af;">CompositionContainer</span>(catalog);</pre>
<p>Enfin avant d’appeler la méthode SatisfyImports, nous devons également ajouter une propriété, décorée de l’attribut ImportMany.</p>
<pre class="code">[<span style="color: #2b91af;">ImportMany</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ViewModelBase</span>),
    RequiredCreationPolicy = <span style="color: #2b91af;">CreationPolicy</span>.NonShared)]
<span style="color: blue;">public </span><span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">Lazy</span>&lt;<span style="color: #2b91af;">ViewModelBase</span>, <span style="color: #2b91af;">IViewModelMetadata</span>&gt;&gt;
    LazyViewModels { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>En y regardant d’un peu plus près, plusieurs points sont à mettre en avant ici.</p>
<ul>
<li>
<div>L’attribut ImportMany sert à spécifier au conteneur MEF qu’il doit remplir la collection avec tous les Exports basés sur le type ViewModelBase</div>
</li>
<li>
<div>L’interface IViewModelMetadata qui a une propriété Name indique que nos Export ont des métadonnées associées.</div>
</li>
<li>
<div>Le type Lazy signifie que l’on diffère l’instanciation des ViewModels. Cependant les métadonnées, sont accessibles.</div>
</li>
<li>
<div>La propriété RequiredCreationPolicy = <span style="color: #2b91af;">CreationPolicy</span>.NonShared dit qu’à chaque nouvel appel à une part, une nouvelle instance sera créée.</div>
</li>
</ul>
<p>Une fois ces étapes réalisées, nous pouvons appeler la méthode SatisfyImportOnce du conteneur pour charger les différentes Parts</p>
<pre class="code">mefContainer.SatisfyImportsOnce(<span style="color: blue;">this</span>);</pre>
<p>Dernière étape pour que notre resolver soit complet, implémenter la méthode Resolv que contient l’interface IViewModelResolver. Comme les métadonnées sont accessibles, nous allons nous aider de linq pour les parcourir et récupérer le viewModel correspondant.</p>
<pre class="code"><span style="color: blue;">public </span><span style="color: #2b91af;">ViewModelBase </span>Resolve(<span style="color: blue;">string </span>viewModelName)
       {
          <span style="color: blue;">var </span>lazyVM = LazyViewModels
               .Where(p =&gt; p.Metadata.Name == viewModelName)
               .FirstOrDefault();
           <span style="color: blue;">if </span>(lazyVM != <span style="color: blue;">null</span>)
               <span style="color: blue;">return </span>lazyVM.Value;

           <span style="color: blue;">return null</span>;
       }</pre>
<p>Afin de pouvoir utiliser le ViewModel Locator, nous allons l’ajouter en tant que ressource dans App.xaml, ainsi il sera disponible à partir de l’ensemble des vues de l’application. Nous allons également en profiter pour spécifier au Locator que l’on souhaite utiliser le resolver MEFResolver que l’on vient tout juste de créer.</p>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">Application.Resources</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">locator</span><span style="color: blue;">:</span><span style="color: #a31515;">ViewModelLocator </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="MEFLocator"&gt;
            &lt;</span><span style="color: #a31515;">locator</span><span style="color: blue;">:</span><span style="color: #a31515;">ViewModelLocator.Resolver</span><span style="color: blue;">&gt;
                &lt;</span><span style="color: #a31515;">resolver</span><span style="color: blue;">:</span><span style="color: #a31515;">MEFResolver
                    </span><span style="color: red;">DirectoryPath</span><span style="color: blue;">="MyPath"   /&gt;
            &lt;/</span><span style="color: #a31515;">locator</span><span style="color: blue;">:</span><span style="color: #a31515;">ViewModelLocator.Resolver</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">locator</span><span style="color: blue;">:</span><span style="color: #a31515;">ViewModelLocator</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">Application.Resources</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Pour associer un viewModel à une vue, il vous reste juste à renseigner sa propriété DataContext. Prenons pour exemple la fenêtre principale de notre application.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">Window </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Class</span><span style="color: blue;">="MVVMTemplate.MainView"
             </span><span style="color: red;">DataContext</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Source</span><span style="color: blue;">={</span><span style="color: #a31515;">StaticResource </span><span style="color: red;">MEFLocator</span><span style="color: blue;">},
                            </span><span style="color: red;">Path</span><span style="color: blue;">=[MainViewModel]}"&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Comme vous pouvez le remarquer, on indique “MainViewModel” au niveau de la propriété Path. Alors vous allez me dire et la classe ViewModel où est-elle ? Justement j’allais y venir !</p>
<p>De manière à fournir au designer VS 2010 et à Blend des données, nous allons créer deux ViewModels distincts.  On pourrait en utiliser qu’un seul et s’appuyer sur les méthodes permettant de détecter si on  est en mode design ou pas, mais personnellement, je trouve que le ViewModel devient illisible.</p>
<p>Pour définir nos deux ViewModels, nous allons donc:</p>
<ul>
<li>
<div>définir une interface IMainViewModel sur laquelle ils vont s’appuyer pour connaître les opérations qu’ils doivent implémenter. Dans notre cas ca va être très simple puisqu’elle contient une seule propriété nommée Name.</div>
</li>
</ul>
<blockquote>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IMainViewModel
   </span>{
       <span style="color: blue;">string </span>Name { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
   }</pre>
</blockquote>
<ul>
<li>Les faire hériter d’une classe de base nommée ViewModelBase qui implémente notamment l’interface INotifyPropertyChanged.</li>
<li>Ajouter deux attributs, en rapport avec le fait que l’on souhaite passer par un resolver MEF.
<ul>
<li>PartCreationPolicy, pour préciser qu’il ne s’agit pas d’un ViewModel partagé, mais qu’une nouvelle instance devra être créée.
<pre class="code">[<span style="color: #2b91af;">PartCreationPolicy</span>(<span style="color: #2b91af;">CreationPolicy</span>.NonShared)</pre>
</li>
<li>
<div>ViewModelExport qui correspond à un attribut d’export personnalisé, qui englobe les métadonnées. Pour plus d’informations sur ce point, je vous redirige sur <a href="http://blog.experida.fr/2010/08/25/wpf-mef-e28093-exporter-des-donnees-2/" target="_blank">un des derniers billets</a> que j’ai écris.</div>
<pre class="code">[<span style="color: #2b91af;">ViewModelExport</span>(Name = <span style="color: #a31515;">"MainViewModel"</span>)]</pre>
<pre class="code">[<span style="color: #2b91af;">MetadataAttribute</span>]
   [<span style="color: #2b91af;">AttributeUsage</span>(<span style="color: #2b91af;">AttributeTargets</span>.Class,
       AllowMultiple = <span style="color: blue;">false</span>, Inherited = <span style="color: blue;">true</span>)]
   <span style="color: blue;">public class </span><span style="color: #2b91af;">ViewModelExport </span>: <span style="color: #2b91af;">ExportAttribute
   </span>{
       <span style="color: blue;">public string </span>Name { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

       <span style="color: blue;">public </span>ViewModelExport()
           : <span style="color: blue;">base</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ViewModelBase</span>))
       {
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></li>
</ul>
</li>
</ul>
<p>Au niveau de la métadonnée, vous pouvez voir que l’on retrouve le nom “MainViewModel”.</p>
<p>Voici le ViewModel complet.</p>
<pre class="code">[<span style="color: #2b91af;">PartCreationPolicy</span>(<span style="color: #2b91af;">CreationPolicy</span>.NonShared)]
    [<span style="color: #2b91af;">ViewModelExport</span>(Name = <span style="color: #a31515;">"MainViewModel"</span>)]
    <span style="color: blue;">public class </span><span style="color: #2b91af;">MainViewModel </span>: <span style="color: #2b91af;">ViewModelBase</span>, <span style="color: #2b91af;">IMainViewModel
    </span>{
        <span style="color: green;">//[ImportingConstructor]
        </span><span style="color: blue;">public </span>MainViewModel()
        {
            <span style="color: blue;">this</span>.Name = <span style="color: #a31515;">"MainViewModel Template"</span>;
        }

        <span style="color: blue;">private string </span>name;
        <span style="color: blue;">public string </span>Name
        {
            <span style="color: blue;">get </span>{ <span style="color: blue;">return this</span>.name; }
            <span style="color: blue;">set
            </span>{
                <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= name)
                {
                    <span style="color: blue;">this</span>.name = <span style="color: blue;">value</span>;
                    <span style="color: blue;">base</span>.RaisePropertyChanged&lt;<span style="color: #2b91af;">MainViewModel</span>,
                         <span style="color: blue;">string</span>&gt;(m =&gt; m.Name);
                }
            }
        }
    }</pre>
<p>Sur le constructeur, vous noterez  aussi la présence d’un attribut [ImportingConstructor] que j’ai mis en commentaire ici. Mais vous pouvez l’utiliser pour injecter dans le ViewModel différents services.</p>
<p>Le ViewModel utilisé en mode design est exactement le même excepté le texte assigné à la propriété Name et les différents attributs ici présents qu’il n’utilise pas.</p>
<p>Si vous lancez l’application maintenant vous devriez voir un écran comme celui-ci.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/09/image.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/09/image_thumb.png" border="0" alt="image" width="425" height="344" /></a></p>
<p>Dernier point, pour terminer ce billet, nous devons référencer le ViewModel design qui se trouve dans une autre assembly et l’ajouter en tant que type devant être utilisé pour le design avec la propriété d:DataContext</p>
<pre class="code">  <span style="color: red;">d</span><span style="color: blue;">:</span><span style="color: red;">DataContext</span><span style="color: blue;">="{</span><span style="color: #a31515;">d</span><span style="color: blue;">:</span><span style="color: #a31515;">DesignInstance </span><span style="color: red;">design</span><span style="color: blue;">:</span><span style="color: red;">DesignMainViewModel</span><span style="color: blue;">, </span><span style="color: red;">IsDesignTimeCreatable</span><span style="color: blue;">=True}"</span><span style="color: blue;">
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>En procédant ainsi, vous pourrez notamment utiliser les dernières améliorations faites dans le designer de la version VS 2010 pour créer vos Binding.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/09/image1.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/09/image_thumb1.png" border="0" alt="image" width="462" height="268" /></a></p>
<p>Et voilà les données sont également accessibles dans VS et Blend.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/09/image2.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/09/image_thumb2.png" border="0" alt="image" width="494" height="249" /></a></p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/09/image3.png"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/09/image_thumb3.png" border="0" alt="image" width="476" height="250" /></a></p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/09/MVVMLocator.zip" target="_blank">Télécharger les sources.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/09/12/viewmodel-locator-resolver-et-e2809cblendabilitee2809d/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MEF et DirectoryCatalog Refresh</title>
		<link>http://blog.experida.fr/2010/09/08/mef-et-directorycatalog-refresh/</link>
		<comments>http://blog.experida.fr/2010/09/08/mef-et-directorycatalog-refresh/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 21:24:02 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[mef]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[DirectoryCatalog]]></category>
		<category><![CDATA[Refresh]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/09/08/mef-et-directorycatalog-refresh/</guid>
		<description><![CDATA[Dans le billet précédent, nous avions développé une application d’export de données, dans laquelle les différents modules la composant étaient découverts via MEF. Les dll étaient déposées dans un répertoire nommé extensions. Pour arriver à mettre en place cette petite application de démo, le DirectoryCatalog avait notamment été utilisé.  Ce que je vous propose de [...]]]></description>
			<content:encoded><![CDATA[<p>Dans le billet <a href="http://blog.experida.fr/2010/08/25/wpf-mef-e28093-exporter-des-donnees-2/" target="_blank">précédent</a>, nous avions développé une application d’export de données, dans laquelle les différents modules la composant étaient découverts via MEF. Les dll étaient déposées dans un répertoire nommé extensions.</p>
<p>Pour arriver à mettre en place cette petite application de démo, le DirectoryCatalog avait notamment été utilisé. <span id="more-201"></span></p>
<p>Ce que je vous propose de voir aujourd’hui est la mise en place d’un moyen de détection pour tout ajout d’une nouvelle dll dans le répertoire extensions. Le but final étant de notifier l’utilisateur lors de cet ajout, ainsi que la mise à jour de l’interface. Pour cela, nous partons du principe que seule la dll d’export XML est présente dans le dossier. Nous ajouterons ensuite la dll d’export Excel, de manière à voir si le résultat obtenu est correcte.</p>
<p>Au lieu d’instancier la classe DirectoryCatalog dans le BootStrapper, je vous propose de créer une nouvelle classe que l’on appellera AutoRefreshDirectoryCatalog et qui hérite de DirectoryCatalog. Ensuite ajoutez lui la propriété NotifyOnDirectoryChanged de type bool pour indiquer si l’on souhaite activer ou désactiver la mise à jour du catalogue. Enfin mettez en place la surveillance grâce à la classe FileSystemWatcher</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">AutoRefreshDirectoryCatalog </span>: <span style="color: #2b91af;">DirectoryCatalog
   </span>{

       <span style="color: blue;">public bool </span>NotifyOnDirectoryChanged { <span style="color: blue;">get</span>; <span style="color: blue;">private set</span>; }

       <span style="color: blue;">public </span>AutoRefreshDirectoryCatalog(<span style="color: blue;">string </span>path)
           : <span style="color: blue;">this</span>(path, <span style="color: blue;">false</span>)
       { }

       <span style="color: blue;">public </span>AutoRefreshDirectoryCatalog(<span style="color: blue;">string </span>path,
           <span style="color: blue;">bool </span>notifyOnDirectoryChanged)
           : <span style="color: blue;">base</span>(path)
       {
           <span style="color: blue;">this</span>.NotifyOnDirectoryChanged = notifyOnDirectoryChanged;

           <span style="color: blue;">if </span>(notifyOnDirectoryChanged)
           {
               <span style="color: #2b91af;">FileSystemWatcher </span>fsw = <span style="color: blue;">new </span><span style="color: #2b91af;">FileSystemWatcher</span>(path, <span style="color: #a31515;">"*.dll"</span>);
               fsw.EnableRaisingEvents = <span style="color: blue;">true</span>;
               fsw.Created += (s, e) =&gt;
               {
                   <span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Nouvelle dll ajoutée"</span>);
                   Refresh();
               };
           }

       }

   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Comme vous pouvez le remarquer, après avoir créé le FileSystemWatcher et avoir activé la notification , nous nous abonnons à l’event Created, qui va nous permettre de savoir dès qu’une nouvelle dll est ajoutée. Notez au passage, l’application d’un filtre “*.dll”.</p>
<p>Lorsque le handler lié à l’event Created est appelé, nous demandons simplement au catalogue de parcourir de nouveau le répertoire extensions et de se mettre à jour via la méthode Refresh.</p>
<p>Maintenant que cette classe est terminée, nous allons nous tourner à nouveau vers la classe BootStrapper où se trouve le CompositionContainer. Il possède un event Changed qui est appelé dès lors qu’un rafraichissement d’un de ses catalogues a été fait. Quel utilité me direz-vous ? Cela nous permet tout simplement de savoir quand est ce que le container est à jour et à partir de là nous pouvons mettre à jour l’interface en recréant la collection de plugins disponibles via la méthode RefreshPluginList du viewModel principal de l’application.</p>
<pre class="code">arCatalog.Changed += (s, e) =&gt;
                {
                    MainViewModel.RefreshPluginList();
                };</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue;">public void </span>RefreshPluginList()
       {
           PluginsName = <span style="color: blue;">new </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: blue;">string</span>&gt;();

           <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>plugin <span style="color: blue;">in
               this</span>.saveService.AvailablePlugins)
           {
               PluginsName.Add(plugin.Metadata.Name);
           }
       }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Vous pouvez maintenant lancer l’application et ajouter la dll d’export Excel dans le répertoire extensions. La première chose que vous allez voir est une message box de notification. Ensuite déroulez la liste en bas de l’application. En plus d’XML, vous devriez voir maintenant Excel.</p>
<p>Vous pouvez télécharger les sources  <a href="http://blog.experida.fr/wp-content/uploads/2010/09/MEFRefresh.zip" target="_blank">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/09/08/mef-et-directorycatalog-refresh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF / MEF &#8211; Exporter des donn&#233;es</title>
		<link>http://blog.experida.fr/2010/08/25/wpf-mef-e28093-exporter-des-donnees-2/</link>
		<comments>http://blog.experida.fr/2010/08/25/wpf-mef-e28093-exporter-des-donnees-2/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 19:52:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[mef]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[ComposeParts]]></category>
		<category><![CDATA[CompositionContainer]]></category>
		<category><![CDATA[Démarrage avec MEF]]></category>
		<category><![CDATA[Export]]></category>
		<category><![CDATA[Import]]></category>
		<category><![CDATA[Introduction MEF]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Plugins]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/08/25/wpf-mef-e28093-exporter-des-donnees-2/</guid>
		<description><![CDATA[Qu’est ce que MEF ? MEF est un Framework permettant de développer des applications modulaires, composées de Parts. Vous trouverez d’un côté les Parts “Export” qui fournissent des services et de l’autre les Parts “Import” qui utilisent ces services. Dans l’utilisation de MEF que j’ai pu faire jusqu’à maintenant, j’ai tendance à dire qu’on a [...]]]></description>
			<content:encoded><![CDATA[<p>Qu’est ce que MEF ?</p>
<p>MEF est un Framework permettant de développer des applications modulaires, composées de Parts. Vous trouverez d’un côté les Parts “Export” qui fournissent des services et de l’autre les Parts “Import” qui utilisent ces services. Dans l’utilisation de MEF que j’ai pu faire jusqu’à maintenant, j’ai tendance à dire qu’on a d’un côté l’application Core et de l’autre un ensemble de plugins respectant un contrat pour chaque service attendu.</p>
<p><span id="more-197"></span></p>
<p>Dans ce billet, je vous propose de voir le développement de l’application core, et d’un plugin. Le second sera présent dans les sources disponibles à la fin du billet. Pour y parvenir considérons les points suivants:</p>
<ul>
<li>
<div>Notre application est une application de type client lourd</div>
</li>
<li>
<div>Au niveau de l’UI nous affichons une liste d’objet Employee et proposons à l’utilisateur plusieurs possibilités pour exporter ses données</div>
<ul>
<li>
<div>La première se fera via un fichier XML</div>
</li>
<li>
<div>La seconde quant à elle se fera vers un fichier Excel.</div>
</li>
</ul>
</li>
<li>
<div>L’application utilise le pattern MVVM</div>
</li>
<li>
<div>Le model est constitué d’une seule entité nommée Employee.</div>
</li>
</ul>
<p>Le but de ce billet n’est pas de voir comment implémenter MVVM avec WPF, je considère que vous savez déjà le faire. A ce titre, nous allons partir d’un projet de base avec le ViewModel principal déjà créé. Pour cela, vous pouvez utiliser le Template de création de projet <a href="http://blog.experida.fr/2010/08/19/template-vs-2010-pour-la-creation-de28099une-application-wpf-avec-le-pattern-mvvm/" target="_blank">suivant</a>.</p>
<p><span style="text-decoration: underline;"><strong>1- Création du model</strong></span></p>
<p>Comme dit plus haut, notre model va rester simple pour la démonstration. Il sera uniquement constitué d’une entité Employee ainsi que de quatre propriétés: LastName, FirstName, Age et Job. Vous remarquerez au passage que la classe hérite de NotifiableObjectBase qui donne la possibilité de notifier le changement d’une des propriétés. (Son code sera dans le zip à la fin du billet).</p>
<p><strong>Code classe Employee:</strong></p>
<div>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Employee </span>: <span style="color: #2b91af;">NotifiableObjectBase
  </span>{
      <span style="color: blue;">private string </span>lastName;
      <span style="color: blue;">public string </span>LastName
      {
          <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>lastName; }
          <span style="color: blue;">set
          </span>{
              <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= lastName)
              {
                  lastName = <span style="color: blue;">value</span>;
                  <span style="color: blue;">base</span>.RaisePropertyChanged&lt;<span style="color: blue;">string</span>&gt;(() =&gt; LastName);
              }
          }
      }

      <span style="color: blue;">private string </span>firstname;
      <span style="color: blue;">public string </span>FirstName
      {
          <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>firstname; }
          <span style="color: blue;">set
          </span>{
              <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= firstname)
              {
                  firstname = <span style="color: blue;">value</span>;
                  <span style="color: blue;">base</span>.RaisePropertyChanged&lt;<span style="color: blue;">string</span>&gt;(() =&gt; FirstName);
              }
          }
      }

      <span style="color: blue;">private int </span>age;
      <span style="color: blue;">public int </span>Age
      {
          <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>age; }
          <span style="color: blue;">set
          </span>{
              <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= age)
              {
                  age = <span style="color: blue;">value</span>;
                  <span style="color: blue;">base</span>.RaisePropertyChanged&lt;<span style="color: blue;">int</span>&gt;(() =&gt; Age);
              }
          }
      }

      <span style="color: blue;">private string </span>job;
      <span style="color: blue;">public string </span>Job
      {
          <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>job; }
          <span style="color: blue;">set
          </span>{
              <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= job)
              {
                  job = <span style="color: blue;">value</span>;
                  <span style="color: blue;">base</span>.RaisePropertyChanged&lt;<span style="color: blue;">string</span>&gt;(() =&gt; Job);
              }
          }
      }

  }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;"><strong>2- MEF – Création du contrat pour les plugins.</strong></span></p>
<p>De manière à ce qu’un plugin soit accepté par l’application, il doit respecter un contrat. En code ce contrat est représenté par une interface, qui impose donc au plugin d’implémenter les méthodes et propriétés qui y sont spécifiées.</p>
<p>Dans notre cas, comme nous voulons donner la possibilité à l’utilisateur d’exporter une liste de données vers un fichier Excel et XML, nous allons juste ajouter une méthode Save à notre interface.</p>
<div>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">ISave
</span>{
    <span style="color: blue;">void </span>Save&lt;T&gt;(<span style="color: #2b91af;">List</span>&lt;T&gt; listToExport);
}</pre>
</div>
<p>La méthode prend en paramètre une liste de données générique, ainsi nous pourrons par la suite, passer autre chose que des entités Employee si nécessaire.</p>
<p><strong><span style="text-decoration: underline;">3 – Création d’un plugin</span></strong></p>
<p>Maintenant que le contrat est créé, nous pouvons passer à la création du plugin. Dans un premier temps, nous allons créer un seul plugin correspondant à l’export vers un fichier XML.</p>
<p>Pour la création du plugin, commencez par créer une nouvelle librairie. Cette librairie ne sera pas ajoutée en tant que référence dans un projet de la solution. Toutefois, nous allons spécifier une ligne de commande Post Build Event sur le projet pour que la dll finale soit copiée dans un répertoire spécifique aux plugins que nous allons nommer Extensions.</p>
<p>Allez dans les propriétés du projet et après avoir sélectionné l’onglet “Build Events”, ajoutez la ligne suivante:</p>
<p>copy &#8220;$(OurDir)&#8221;* &#8220;$(SolutionDir)MEFDemo\bin\$(ConfigurationName)\Extensions\&#8221;</p>
<p>Une fois cette étape réalisée, ajoutons une classe que l’on appellera SaveToXml. Faites lui ensuite implémenter l’interface ISave. Dans la méthode générique Save nous allons utiliser une librairie que j’ai développé pour la sérialisation des données.</p>
<div>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">SaveToXml </span>: <span style="color: #2b91af;">ISave
    </span>{
        <span style="color: blue;">public void </span>Save&lt;T&gt;(<span style="color: #2b91af;">List</span>&lt;T&gt; listToExport)
        {
            <span style="color: blue;">if </span>(listToExport == <span style="color: blue;">null</span>)
                <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"listToExport"</span>);

            <span style="color: blue;">string </span>currentPath = <span style="color: #2b91af;">Directory</span>.GetCurrentDirectory();
            <span style="color: #2b91af;">XmlHelper</span>.SaveDataToXml&lt;<span style="color: #2b91af;">List</span>&lt;T&gt;&gt;(
                <span style="color: #2b91af;">Path</span>.Combine(currentPath,<span style="color: #a31515;">"export.xml"</span>),
                listToExport,
                <span style="color: blue;">null</span>);
        }
    }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Encore une fois pour rester concentré sur le sujet, je ne montrerai pas ici le code de la librairie de sérialisation, mais sachez qu’il sera disponible à la fin du billet.</p>
<p>En plus du fait que nous ayons besoin d’utiliser un contrat pour notre plugin, le Framework MEF à besoin qu’on ajoute un attribut ExportAttribute sur notre classe pour spécifier qu’il participe en tant qu’élément dans la composition de l’application dans le cadre du contrat ISave.</p>
<div>
<pre class="code"> [<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ISave</span>))]
 <span style="color: blue;">public class </span><span style="color: #2b91af;">SaveToXml </span>: <span style="color: #2b91af;">ISave
</span></pre>
</div>
<p>Enfin, nous allons ajouter une dernier attribut ExportMetadataAttribute qui comme son nom l’indique permet de définir des métadonnées sur notre classe. Ces métadonnées permettent d’ajouter des informations concernant le plugin également appelé Part dans le langage MEF. </p>
<p>Dans notre cas nous allons juste ajouter une méta pour donner un nom et identifier facilement le plugin auquel on à faire.</p>
<div>
<pre class="code">[<span style="color: #2b91af;">ExportMetadata</span>(<span style="color: #a31515;">"Name"</span>,<span style="color: #a31515;">"xml"</span>)]
[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ISave</span>))]
<span style="color: blue;">public class </span><span style="color: #2b91af;">SaveToXml </span>: <span style="color: #2b91af;">ISave
</span></pre>
</div>
<p>Nous pourrions nous arrêter là en ce qui concerne cette Part, mais nous allons développer notre propre attribut d’export pour les raisons suivantes.</p>
<ul>
<li>
<div>Spécifier un seul attribut pour le contrat de l’export et les métadonnées.</div>
</li>
<li>
<div>Utiliser des métadonnées fortement typées.</div>
</li>
</ul>
<p>Pour cela notre attribut doit hériter de ExportAttribute se trouvant dans System.ComponentModel.Composition. Pour indiquer qu’il agit également comme un attribut de métadonnées, il nous faut ajouter sur notre attribut l’attribut MetadataAttribute. Enfin nous avons vu que la seule méta nécessaire ici est Name, nous allons donc ajouter une propriété Name de type string.</p>
<div>
<pre class="code">[<span style="color: #2b91af;">MetadataAttribute</span>]
    [<span style="color: #2b91af;">AttributeUsage</span>(<span style="color: #2b91af;">AttributeTargets</span>.Class,
        AllowMultiple = <span style="color: blue;">false</span>,
        Inherited = <span style="color: blue;">false</span>)]
    <span style="color: blue;">public sealed class </span><span style="color: #2b91af;">SaveExportAttribute </span>: <span style="color: #2b91af;">ExportAttribute
    </span>{

        <span style="color: blue;">public </span>SaveExportAttribute()
            : <span style="color: blue;">base</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ISave</span>))
        {
        }

        <span style="color: blue;">public string </span>Name { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

    }</pre>
</div>
<p>Maintenant que cela est fait, nous allons développer un service permettant d’accéder aux plugins ajoutés dans le répertoire Extensions et faire en sorte qu’il soit injecté via Unity dans le ViewModel nommé MainViewModel.</p>
<p>Pour que ce service soit par la suite facilement mockable, nous allons passer par une interface.</p>
<p>Ce que nous voulons avec ce service, c’est avoir:</p>
<ul>
<li>
<div>une liste des plugins existant pour l’export.</div>
</li>
<li>
<div>une méthode d’export</div>
</li>
</ul>
<div>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">ISaveService
   </span>{
       <span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">Lazy</span>&lt;<span style="color: #2b91af;">ISave</span>,<span style="color: #2b91af;">ISaveMetadata</span>&gt;&gt; AvailablePlugins { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
       <span style="color: blue;">void </span>Save&lt;T&gt;(<span style="color: blue;">string </span>pluginName, <span style="color: #2b91af;">List</span>&lt;T&gt; list);
   }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Regardez la propriété AvailablePlugins.</p>
<p>Vous remarquerez l’utilisation du type Lazy en tant qu’élément du IEnumerable&lt;T&gt;.  Ce type, nouveau dans le Framework 4, permet de différer la création d’un objet.</p>
<p>En regardant d’un peu plus près la définition du type Lazy, on voit qu’on lui spécifie ici un deuxième type ISaveMetadata.</p>
<p>Mef apporte une surcharge du type Lazy, avec lequel on peut également passer des métadonnées, et c’est là tout l’intérêt de la chose. Vous pouvez parcourir les métadonnées en quête d’informations avant même que l’objet soit instancié.</p>
<p>Mais revenons au type ISaveMetadata. Dans notre exemple, il s’agit d’une interface dans laquelle on ajoute les données / métadonnées que l’on veut accessibles au client, ici le Name. En interne MEF, va se charger de créer un classe proxy implémentant cette interface et faire le mapping avec les métadonnées ajoutées avec ExportMetadata ou le custom attribute  SaveExportAttribute dans notre cas.</p>
<div>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">ISaveMetadata
</span>{
    <span style="color: blue;">string </span>Name { <span style="color: blue;">get</span>; }
}</pre>
</div>
<p>A présent, après avoir vu la propriété AvailablePlugins, il nous reste la méthode Save à inspecter. Rien de bien compliqué en ce qui la concerne. On voit qu’il s’agit d’une méthode générique ce qui permet éventuellement de faire des exports basés sur un autre type que Employee, et qu’on lui passe en paramètre le nom du plugin qu’elle doit utiliser pour effectuer cet export.</p>
<p>Du côté de l’implémentation réalisée dans ce projet, on retrouve ce que l’on vient d’expliquer.</p>
<p>Notez quand même la présence de l’attribut ImportMany sur la propriété AvailablesPlugins pour indiquer à MEF qu’il doit découvrir toutes les Parts Export implémentant l’interface ISave</p>
<p>Dans la méthode Save, nous récupérons simplement le bon plugin grâce à une petite requête linq. A cet instant précis, le plugin n’est pas encore instancié. Un peu plus loin l’instance de type ISave est enfin créée via l’appel à la propriété Value. Il ne reste plus qu’à appeler la méthode qui je le rappelle se trouve au  niveau de l’interface ISave.</p>
<div>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">SaveService </span>: <span style="color: #2b91af;">ISaveService
   </span>{
       [<span style="color: #2b91af;">ImportMany</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ISave</span>))]
       <span style="color: blue;">public </span><span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">Lazy</span>&lt;<span style="color: #2b91af;">ISave</span>,<span style="color: #2b91af;">ISaveMetadata</span>&gt;&gt;
           AvailablePlugins { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

       <span style="color: blue;">public void </span>Save&lt;T&gt;(<span style="color: blue;">string </span>pluginName, <span style="color: #2b91af;">List</span>&lt;T&gt; list)
       {
           <span style="color: blue;">var </span>lazyPlugin = AvailablePlugins
               .FirstOrDefault(p =&gt; p.Metadata.Name == pluginName);
           <span style="color: blue;">if </span>(lazyPlugin == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new </span><span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Invalid plugin name"</span>);

           <span style="color: green;">//plugin instanciation
           </span><span style="color: blue;">var </span>plugin = lazyPlugin.Value;
           <span style="color: blue;">if </span>(plugin == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new </span><span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Plugin is not available"</span>);

           plugin.Save&lt;T&gt;(list);
       }
   }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Au début de ce billet, j’avais précisé que la démo utilisait le pattern MVVM. Pour rendre ce service accessible au ViewModel, nous allons l’injecter via Unity dans son constructeur.</p>
<div>
<pre class="code"><span style="color: blue;">public </span>MainViewModel(<span style="color: #2b91af;">IMainView </span>mainView, <span style="color: #2b91af;">ISaveService </span>saveService)</pre>
</div>
<p>Dans notre ViewModel, nous allons ajouter une collection de type string qui va contenir les noms des plugins disponibles. Cette liste est construite à partir des informations que le service SaveService nous fait parvenir. La vue n’aura plus qu’à se binder pour afficher une liste de ces valeurs.</p>
<div>
<pre class="code"><span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>plugin <span style="color: blue;">in this</span>.saveService.AvailablePlugins)
{
    PluginsName.Add(plugin.Metadata.Name);
}</pre>
</div>
<div>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">ComboBox   </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">PluginsName</span><span style="color: blue;">}" /&gt;
</span></pre>
</div>
<p>Enfin pour avoir quelques données à exporter, on créé également une ObservableCollection de type Employee, que la vue va afficher dans un DataGrid, et on lui ajoute des Employee, tous les même ici pour simplifier la démo.</p>
<div>
<pre class="code"><span style="color: blue;">public </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">Employee</span>&gt; Employees { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
</div>
<div>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">DataGrid </span><span style="color: red;">Grid.Row</span><span style="color: blue;">="1" </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Employees</span><span style="color: blue;">}" /&gt;
</span></pre>
</div>
<div>
<pre class="code"><span style="color: blue;">for </span>(<span style="color: blue;">int </span>i = 0; i &lt; 20; i++)
               Employees.Add(<span style="color: blue;">new </span><span style="color: #2b91af;">Employee
               </span>{
                   Age = 25,
                   FirstName = <span style="color: #a31515;">"Alexandre"</span>,
                   LastName = <span style="color: #a31515;">"Arnaudet"</span>,
                   Job = <span style="color: #a31515;">"Ingénieur d'études" </span>});</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dernier  point à régler pour terminer l’UI et le ViewModel, déclencher l’appel à la méthode Save du service. Pour cela, ajoutons une ICommand dans le ViewModel que l’on va nommer SelectExportTypeCommand. Comme nous utilisons une ICommand de type RelayCommand, il nous faut également préciser le handler appelé lors de l’exécution de la commande, ainsi qu’une méthode indiquant si l’appel de la commande peut avoir lieu.</p>
<div>
<pre class="code"><span style="color: blue;">public </span><span style="color: #2b91af;">ICommand </span>SelectExportTypeCommand
       {
           <span style="color: blue;">get
           </span>{
               <span style="color: blue;">if </span>(selectExportTypeCommand == <span style="color: blue;">null</span>)
                   selectExportTypeCommand =
                       <span style="color: blue;">new </span><span style="color: #2b91af;">RelayCommand</span>(
                           param =&gt; Export(param),
                           param =&gt; CanExport());

               <span style="color: blue;">return </span>selectExportTypeCommand;
           }
       }

       <span style="color: blue;">private void </span>Export(<span style="color: blue;">object </span>param)
       {

           <span style="color: blue;">this</span>.saveService
               .Save&lt;<span style="color: #2b91af;">Employee</span>&gt;(selectedExportPlugin,
               <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Employee</span>&gt;(Employees));
       }

       <span style="color: blue;">private bool </span>CanExport()
       {
           <span style="color: blue;">return </span>!<span style="color: blue;">string</span>.IsNullOrEmpty(SelectedExportPlugin);
       }</pre>
</div>
<p>Au niveau de l’UI, un simple contrôle de type button utilisant sa propriété Command pour se binder sur la ICommand d’export. Voici un résumé du code XAML représentant l’UI.</p>
<div>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">Grid</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">Grid.RowDefinitions</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">RowDefinition </span><span style="color: red;">Height</span><span style="color: blue;">="30" /&gt;
            &lt;</span><span style="color: #a31515;">RowDefinition </span><span style="color: red;">Height</span><span style="color: blue;">="*" /&gt;
            &lt;</span><span style="color: #a31515;">RowDefinition </span><span style="color: red;">Height</span><span style="color: blue;">="40" /&gt;
        &lt;/</span><span style="color: #a31515;">Grid.RowDefinitions</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="Demo MEF" </span><span style="color: red;">FontSize</span><span style="color: blue;">="24"  /&gt;
        &lt;</span><span style="color: #a31515;">DataGrid </span><span style="color: red;">Grid.Row</span><span style="color: blue;">="1"
                  </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Employees</span><span style="color: blue;">}" /&gt;
        &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Grid.Row</span><span style="color: blue;">="2"
                    </span><span style="color: red;">Orientation</span><span style="color: blue;">="Horizontal"&gt;
            &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="Mode d'export:"
                       </span><span style="color: red;">VerticalAlignment</span><span style="color: blue;">="Center" /&gt;
            &lt;</span><span style="color: #a31515;">ComboBox   </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">PluginsName</span><span style="color: blue;">}"
                        </span><span style="color: red;">Margin</span><span style="color: blue;">="5"
                        </span><span style="color: red;">SelectedItem</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">SelectedExportPlugin</span><span style="color: blue;">}"
                        </span><span style="color: red;">Width</span><span style="color: blue;">="150"/&gt;
            &lt;</span><span style="color: #a31515;">Button </span><span style="color: red;">Content</span><span style="color: blue;">="Exporter" </span><span style="color: red;">Margin</span><span style="color: blue;">="5"
                    </span><span style="color: red;">Command</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">SelectExportTypeCommand</span><span style="color: blue;">}"/&gt;

        &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">Grid</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p> </p>
<p>Avant de lancer l’application, nous allons jeter un coup d’œil à un dernier fichier nommé bootstrapper. Ce fichier est une simple classe appelée depuis App.xaml.cs au démarrage de l’application. On y configure le container unity dans le constructeur.</p>
<div>
<pre class="code"><span style="color: blue;">public </span>BootStrapper()
       {
           container = <span style="color: blue;">new </span><span style="color: #2b91af;">UnityContainer</span>();
           <span style="color: #2b91af;">UnityConfigurationSection </span>section =
               (<span style="color: #2b91af;">UnityConfigurationSection</span>)<span style="color: #2b91af;">ConfigurationManager
               </span>.GetSection(<span style="color: #2b91af;">ConfigurationManager</span>.AppSettings[<span style="color: #a31515;">"UnitySection"</span>]);
           section.Configure(container);
       }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans un second temps, elle s’occupe également dans la méthode Load de faire la résolution du ViewModel principal et d’afficher la vue liée.</p>
<p>L’utilisation de MEF implique la création d’un CompositionContainer, dans lequel on ajoute les Parts qui vont composer l’application. Ici on s’aperçoit que le CompositionContainer est construit à partir d’un catalogue de type DirectoryCatalog qui correspond au répertoire Extensions dans lequel se trouve les dlls avec les Export. Le service SaveService qui contient une propriété AvailablePlugins avec un Attribut Import est également une Part. On utilise donc la méthode ComposePart pour le signaler au container et lui dire de satisfaire les imports présents.</p>
<div>
<pre class="code"><span style="color: blue;">internal void </span>Load()
        {
            <span style="color: blue;">string </span>directoryPath = <span style="color: #2b91af;">Directory</span>.GetCurrentDirectory();
            <span style="color: blue;">string </span>fullPath =
                <span style="color: #2b91af;">Path</span>.Combine(directoryPath,
                <span style="color: #2b91af;">ConfigurationManager</span>.AppSettings[<span style="color: #a31515;">"ExtensionsPath"</span>]);

            <span style="color: blue;">var </span>catalog = <span style="color: blue;">new </span><span style="color: #2b91af;">AggregateCatalog</span>();
            catalog.Catalogs
                .Add(<span style="color: blue;">new </span><span style="color: #2b91af;">DirectoryCatalog</span>(fullPath));

            <span style="color: blue;">var </span>mefContainer = <span style="color: blue;">new </span><span style="color: #2b91af;">CompositionContainer</span>(catalog);
            <span style="color: blue;">var </span>service = container.Resolve&lt;<span style="color: #2b91af;">ISaveService</span>&gt;();
            mefContainer.ComposeParts(service);

            <span style="color: #2b91af;">IMainViewModel </span>mainViewModel =
                container.Resolve&lt;<span style="color: #2b91af;">IMainViewModel</span>&gt;();
            mainViewModel.View.ShowView();
        }
    }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Le développement de l’application est terminé. Si vous la démarrez, vous devriez obtenir le résultat suivant avec juste un option pour l’export: xml. Vous pourrez trouver ce fichier xml dans le répertoire où l’application s’exécute.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/08/image.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/08/image_thumb.png" border="0" alt="image" width="403" height="499" /></a> <a href="http://11011.net/software/vspaste"></a></p>
<p>Nous venons juste de voir que la résolution du ViewModel,  de la View et du Service était faite via Unity, mais après tout on peut très bien utiliser MEF pour réaliser cette opération.</p>
<p>Pour cella il suffit comme on l’a fait avec l’export xml de placer les attributs Export et Import.</p>
<ul>
<li>
<div>Placez l’attribut export sur le ViewModel:</div>
</li>
</ul>
<blockquote>
<div>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IMainViewModel</span>))]</pre>
</div>
</blockquote>
<ul>
<li>
<div>Placez l’attribut ImportingConstructor sur le constructor du ViewModel pour dire à MEF que ses paramètres deviennent des Import.</div>
</li>
</ul>
<blockquote>
<div>
<pre class="code">[<span style="color: #2b91af;">ImportingConstructor</span>]
       <span style="color: blue;">public </span>MainViewModel(<span style="color: #2b91af;">IMainView </span>mainView,
           <span style="color: #2b91af;">ISaveService </span>saveService)</pre>
</div>
</blockquote>
<ul>
<li>
<div>Placez l’attribut Export sur la View</div>
</li>
</ul>
<blockquote>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IMainView</span>))]</pre>
</blockquote>
<ul>
<li>
<div>Placez l’attribut Export sur le SaveService</div>
</li>
</ul>
<blockquote>
<div>
<pre class="code">[<span style="color: #2b91af;">Export</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ISaveService</span>))]</pre>
</div>
</blockquote>
<p> </p>
<ul>
<li>
<div>Modifiez le bootstrapper de manière à ajouter une propriété IMainViewModel avec un Import.</div>
</li>
</ul>
<blockquote>
<div>
<pre class="code">[<span style="color: #2b91af;">Import</span>]
     <span style="color: blue;">public </span><span style="color: #2b91af;">IMainViewModel </span>MainViewModel { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</pre>
</div>
</blockquote>
<ul>
<li>
<div>Faites un ComposePart du bootStrapper pour satisfaire l’import</div>
</li>
</ul>
<blockquote>
<div>
<pre class="code">mefContainer.ComposeParts(<span style="color: blue;">this</span>);</pre>
</div>
</blockquote>
<ul>
<li>
<div>Affichez la vue</div>
</li>
</ul>
<blockquote>
<div>
<pre class="code"><span style="color: blue;">if </span>(MainViewModel != <span style="color: blue;">null</span>)
                MainViewModel.View.ShowView();</pre>
</div>
</blockquote>
<p>Enfin avant de lancer l’application, supprimez les références vers MVVM.ViewModel, MVVM.View et MEFDemo.SaveService, et modifiez les post build event comme pour le plugin xml afin que les dlls soient déposées dans le répertoire Extensions.</p>
<p>Vous pouvez télécharger l’ensemble des sources ci-dessous. Vous y trouverez notamment un deuxième plugin pour l’export de la même liste de données, mais cette fois ci vers excel.</p>
<p>Sources et autres librairies: <a href="http://blog.experida.fr/wp-content/uploads/2010/08/MEF.zip" target="_blank">Télécharger</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/08/25/wpf-mef-e28093-exporter-des-donnees-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Template VS 2010 pour la cr&#233;ation d&#8217;une application WPF avec le pattern MVVM.</title>
		<link>http://blog.experida.fr/2010/08/19/template-vs-2010-pour-la-creation-de28099une-application-wpf-avec-le-pattern-mvvm/</link>
		<comments>http://blog.experida.fr/2010/08/19/template-vs-2010-pour-la-creation-de28099une-application-wpf-avec-le-pattern-mvvm/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 21:20:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Template]]></category>
		<category><![CDATA[VS2010]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/08/20/template-vs-2010-pour-la-creation-de28099une-application-wpf-avec-le-pattern-mvvm/</guid>
		<description><![CDATA[Il m’arrive régulièrement de développer des applications WPF et de mettre également en place le pattern MVVM. Pour éviter de refaire à chaque fois ce développement simple, mais toujours identique, j’ai décidé de me créer un petit Template utilisable sous Visual Studio 2010. Ce Template permet la création automatique de quatre projets: L’application WPF dans [...]]]></description>
			<content:encoded><![CDATA[<p>Il m’arrive régulièrement de développer des applications WPF et de mettre également en place le pattern MVVM. Pour éviter de refaire à chaque fois ce développement simple, mais toujours identique, j’ai décidé de me créer un petit Template utilisable sous Visual Studio 2010.</p>
<p>Ce Template permet la création automatique de quatre projets:</p>
<ul>
<li>
<div>L’application WPF dans laquelle se trouve, un bootstrapper chargé de créer un conteneur Unity pour la résolution des différents services enregistrés dans le fichier de configuration, et la résolution du couple ViewModel / View principal.</div>
</li>
<li>
<div>Un projet contenant les interfaces IMainViewModel et IMainView</div>
</li>
<li>
<div>Un projet contenant le ViewModel</div>
</li>
<li>
<div>Et un dernier avec la vue principale</div>
</li>
</ul>
<p>Vous pouvez télécharger ce Template <a href="http://blog.experida.fr/wp-content/uploads/2010/08/WPF_MVVM_Template.zip" target="_blank">ici</a>. Son contenu n’est réalisé qu’à titre d’exemple. Libre à vous de le modifier comme vous le souhaitez. Pour l’installer, modifiez l’extension en vsix après l’avoir téléchargé et exécutez le.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/08/19/template-vs-2010-pour-la-creation-de28099une-application-wpf-avec-le-pattern-mvvm/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Extraction d&#8217;une dll depuis le GAC</title>
		<link>http://blog.experida.fr/2010/08/19/extraction-de28099une-dll-depuis-le-gac/</link>
		<comments>http://blog.experida.fr/2010/08/19/extraction-de28099une-dll-depuis-le-gac/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 20:57:54 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Dll]]></category>
		<category><![CDATA[extraction]]></category>
		<category><![CDATA[GAC]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/08/19/extraction-de28099une-dll-depuis-le-gac/</guid>
		<description><![CDATA[Dans ce billet je vous propose juste une solution pour extraire une dll du GAC. La dll nommée ci-dessous est utilisée à titre d’exemple. Ouvrez une ligne de commande puis: Allez dans un des répertoires (GAC, GAC_MSIL&#8230;) selon&#160; l&#8217;archi ex: cd windows\assembly\GAC_MSIL Ensuite allez dans le répertoire de l&#8217;assembly souhaitée ex: cd Microsoft.VisualStudio.Zip.9.0 Et enfin&#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Dans ce billet je vous propose juste une solution pour extraire une dll du GAC. La dll nommée ci-dessous est utilisée à titre d’exemple.</p>
<p>Ouvrez une ligne de commande puis:</p>
<ul>
<li>Allez dans un des répertoires (GAC, GAC_MSIL&#8230;) selon&#160; l&#8217;archi
<ul>
<li><b>ex: cd windows\assembly\GAC_MSIL</b> </li>
</ul>
</li>
<li>Ensuite allez dans le répertoire de l&#8217;assembly souhaitée
<ul>
<li><b>ex: cd Microsoft.VisualStudio.Zip.9.0</b> </li>
</ul>
</li>
<li>Et enfin&#160; parcourez l&#8217;arborescence jusqu&#8217;à trouver la dll recherchée </li>
<li>Pour la copier faites juste un copy source destination
<ul>
<li><b>ex: copy Microsoft.VisualStudio.Zip.9.0.dll c:\</b> </li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/08/19/extraction-de28099une-dll-depuis-le-gac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cr&#233;ation d&#8217;une Behavior par un d&#233;veloppeur</title>
		<link>http://blog.experida.fr/2010/07/31/creation-de28099une-behavior-par-un-developpeur/</link>
		<comments>http://blog.experida.fr/2010/07/31/creation-de28099une-behavior-par-un-developpeur/#comments</comments>
		<pubDate>Sat, 31 Jul 2010 20:46:34 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[Behavior]]></category>
		<category><![CDATA[ListBox]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/07/31/creation-de28099une-behavior-par-un-developpeur/</guid>
		<description><![CDATA[Pour vous expliquer plus concrètement  ce qu’est une behavior, je vous renvoie vers le billet de Christian Schormann qui se charge parfaitement de faire ça. Si vous parcourez de temps en temps ce blog vous aurez peut être remarqué qu’un des derniers billets portait sur la synchronisation de listbox lors du déplacement d’une scrollbar. Dans [...]]]></description>
			<content:encoded><![CDATA[<p>Pour vous expliquer plus concrètement  ce qu’est une behavior, je vous renvoie vers le billet de <a href="http://electricbeach.org/?p=147" target="_blank">Christian Schormann</a> qui se charge parfaitement de faire ça.</p>
<p>Si vous parcourez de temps en temps ce blog vous aurez peut être remarqué qu’un des derniers billets portait sur la <a href="http://blog.experida.fr/2010/07/23/wpf-synchroniser-des-listbox-2/" target="_blank">synchronisation de listbox</a> lors du déplacement d’une scrollbar. Dans ce billet je vous propose de voir comment atteindre le même objectif mais en utilisant cette fois une behavior, le gros avantage étant que celle-ci soit utilisable directement sous Blend par un designer.</p>
<p><span id="more-181"></span></p>
<p>Premier point avant de commencer à coder, si vous n’avez pas une version de Blend au moins équivalente à la version 3 installée, veuillez télécharger le sdk <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&amp;displaylang=en" target="_blank">suivant</a>, de manière à pouvoir ajouter une référence sur System.Windows.Interactivity.</p>
<p>Ensuite reprenez le projet lié au billet ci-dessus nommé et ajoutez une classe qu’on appellera ScrollSyncBehavior. Pour indiquer qu’il s’agit de la création d’une behavior, nous allons faire hériter notre classe de la classe de base Behavior&lt;T&gt;, T étant un DependencyObject. Dans notre cas ce DependencyObject correspond à un contrôle de type ListBox.</p>
<p>Une fois cette opération effectuée, surchargez les deux méthodes OnAttached et OnDetaching.</p>
<div>
<pre class="code"><span style="color: blue;">protected override void </span>OnAttached()
{
    <span style="color: blue;">base</span>.OnAttached();
}

<span style="color: blue;">protected override void </span>OnDetaching()
{
    <span style="color: blue;">base</span>.OnDetaching();
}</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Pour cet exemple la behavior est toujours associée à un élément de type Listbox. Vous pouvez le récupérer via la propriété AssociatedObject de la classe de base.</p>
<p>L’élément qui permet  de faire défiler les différents items dans une ListBox est un ScrollViewer. Pour récupérer ce ScrollViewer, nous pouvons parcourir l’arborescence visuelle via la classe helper VisualTreeHelper. Comme au départ, nous ne savons pas qu’elle est la position exacte du ScrollViewer, nous allons utiliser la méthode suivante pour parcourir l’arbre de manière récursive jusqu’à ce que nous tombions dessus. Notez au passage que cette méthode pourrait être transformée pour être utilisée comme une méthode d’extension d’un DependencyObject, mais ce n’est pas le sujet ici.</p>
<div>
<pre class="code"><span style="color: blue;">public static </span>childItem FindVisualChild&lt;childItem&gt;(<span style="color: #2b91af;">DependencyObject </span>obj)
           <span style="color: blue;">where </span>childItem : <span style="color: #2b91af;">DependencyObject
       </span>{
           <span style="color: blue;">for </span>(<span style="color: blue;">int </span>i = 0; i &lt; <span style="color: #2b91af;">VisualTreeHelper</span>.GetChildrenCount(obj); i++)
           {
               <span style="color: #2b91af;">DependencyObject </span>child = <span style="color: #2b91af;">VisualTreeHelper</span>.GetChild(obj, i);
               <span style="color: blue;">if </span>(child <span style="color: blue;">is </span>childItem)
                   <span style="color: blue;">return </span>(childItem)child;
               <span style="color: blue;">else
               </span>{
                   childItem childOfChild = FindVisualChild&lt;childItem&gt;(child);
                   <span style="color: blue;">if </span>(childOfChild != <span style="color: blue;">null</span>)
                       <span style="color: blue;">return </span>childOfChild;
               }
           }
           <span style="color: blue;">return null</span>;
       }</pre>
</div>
<p>Dans la méthode OnAttached récupérez donc le ScrollViewer de l’objet associé.</p>
<div>
<pre class="code"><span style="color: blue;">this</span>.AssociatedObject.Loaded += (s, e) =&gt;
               {
                   <span style="color: #2b91af;">ScrollViewer </span>scrollViewer =
                       FindVisualChild&lt;<span style="color: #2b91af;">ScrollViewer</span>&gt;(<span style="color: blue;">this</span>.AssociatedObject);</pre>
</div>
<p>Pour la suite du code nous nous rapprochons de ce qui avait été fait dans ScrollSync. Ajoutez une DependencyProperty GroupName pour spécifier le groupe de synchronisation auquel participe la ListBox. Reprenez ensuite le code qu’on avait dans OnScrollGroupChanged et modifiez le de manière à refléter le fait qu’on ne s’appuie pas ici sur une propriété attachée pour le nom du groupe.</p>
<div>
<pre class="code"><span style="color: blue;">if </span>(scrollViewer != <span style="color: blue;">null</span>)
 {
   <span style="color: blue;">if </span>(!<span style="color: blue;">string</span>.IsNullOrEmpty(GroupName))
   {
     <span style="color: blue;">if </span>(horizontalScrollOffsets.Keys.Contains(GroupName))
     {
        scrollViewer.ScrollToHorizontalOffset
                     (horizontalScrollOffsets[GroupName]);
     }
     <span style="color: blue;">else
     </span>      horizontalScrollOffsets
                 .Add(GroupName, scrollViewer.HorizontalOffset);

    <span style="color: blue;">if </span>(verticalScrollOffsets.Keys.Contains(GroupName))
    {
       scrollViewer.ScrollToVerticalOffset
                   (verticalScrollOffsets[GroupName]);
    }
    <span style="color: blue;">else
    </span>   verticalScrollOffsets.Add(GroupName, scrollViewer.VerticalOffset);

     <span style="color: blue;">if </span>(!scrollViewers.ContainsKey(scrollViewer))
     {
        scrollViewers.Add(scrollViewer, GroupName);
           scrollViewer.ScrollChanged
              += <span style="color: blue;">new   </span><span style="color: #2b91af;">ScrollChangedEventHandler</span>(ScrollViewer_ScrollChanged);
     }
   }
}</pre>
</div>
<div>
<pre class="code"> <span style="color: blue;">private static void
    </span>ScrollViewer_ScrollChanged(<span style="color: blue;">object </span>sender, <span style="color: #2b91af;">ScrollChangedEventArgs </span>e)
 {
     <span style="color: blue;">if </span>(e.VerticalChange != 0 || e.HorizontalChange != 0)
     {
         <span style="color: blue;">var </span>changedScrollViewer = sender <span style="color: blue;">as </span><span style="color: #2b91af;">ScrollViewer</span>;
         Scroll(changedScrollViewer);
     }
 }

  <span style="color: blue;">private static void </span>Scroll(<span style="color: #2b91af;">ScrollViewer </span>changedScrollViewer)
 {
   <span style="color: blue;">var </span>group = scrollViewers[changedScrollViewer];
   verticalScrollOffsets[group] =
       changedScrollViewer.VerticalOffset;
   horizontalScrollOffsets[group] =
       changedScrollViewer.HorizontalOffset;

   <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>scrollViewer
        <span style="color: blue;">in </span>scrollViewers
           .Where((s) =&gt; s.Value == group &amp;&amp; s.Key != changedScrollViewer))
   {
     <span style="color: blue;">if </span>(scrollViewer.Key.VerticalOffset
            != changedScrollViewer.VerticalOffset)
     {
       scrollViewer.Key
          .ScrollToVerticalOffset(changedScrollViewer.VerticalOffset);
     }

     <span style="color: blue;">if </span>(scrollViewer.Key
          .HorizontalOffset != changedScrollViewer.HorizontalOffset)
     {
       scrollViewer.Key.
           ScrollToHorizontalOffset(changedScrollViewer.HorizontalOffset);
     }
   }
  }
<span style="color: blue;">
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a>La seule différence réside ensuite dans l’ajout de la méthode OnDetaching. Dans cette méthode, nous allons tout simplement nous détacher de l’event ScrollChanged et supprimer le ScrollViewer correspondant de nos listes internes.</p>
<div>
<pre class="code"><span style="color: blue;">protected override void </span>OnDetaching()
       {
           <span style="color: blue;">base</span>.OnDetaching();

           <span style="color: #2b91af;">ScrollViewer </span>scrollViewer
               = FindVisualChild&lt;<span style="color: #2b91af;">ScrollViewer</span>&gt;(<span style="color: blue;">this</span>.AssociatedObject);
           <span style="color: blue;">if </span>(scrollViewers.ContainsKey(scrollViewer))
           {
             scrollViewer.ScrollChanged
               -= <span style="color: blue;">new </span><span style="color: #2b91af;">ScrollChangedEventHandler</span>(ScrollViewer_ScrollChanged);
               scrollViewers.Remove(scrollViewer);
           }

           <span style="color: blue;">if </span>(!scrollViewers.ContainsValue(GroupName))
           {
               <span style="color: blue;">if </span>(horizontalScrollOffsets.ContainsKey(GroupName))
                   horizontalScrollOffsets.Remove(GroupName);

               <span style="color: blue;">if </span>(verticalScrollOffsets.ContainsKey(GroupName))
                   verticalScrollOffsets.Remove(GroupName);
           }
       }</pre>
</div>
<p>Au niveau du code xaml, supprimez la propriété attachée ajoutée au niveau des styles car elle n’a plus de raison d’exister, et ajoutez la behavior dans l’élément ListBox comme ceci.</p>
<div>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">Height</span><span style="color: blue;">="50"&gt;

                &lt;</span><span style="color: #a31515;">i</span><span style="color: blue;">:</span><span style="color: #a31515;">Interaction.Behaviors</span><span style="color: blue;">&gt;
                    &lt;</span><span style="color: #a31515;">local</span><span style="color: blue;">:</span><span style="color: #a31515;">ScrollSyncBehavior </span><span style="color: red;">GroupName</span><span style="color: blue;">="GroupTest"/&gt;
                &lt;/</span><span style="color: #a31515;">i</span><span style="color: blue;">:</span><span style="color: #a31515;">Interaction.Behaviors</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p>i pointant sur System.Windows.Interactivity</p>
<div>
<pre class="code">        <span style="color: red;">xmlns</span><span style="color: blue;">:</span><span style="color: red;">i</span><span style="color: blue;">="clr-namespace:System.Windows.Interactivity;
        assembly=System.Windows.Interactivity"
</span></pre>
</div>
<p>Retrouvez les sources <a href="http://blog.experida.fr/wp-content/uploads/2010/07/ScrollSyncBehavior.zip" target="_blank">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/07/31/creation-de28099une-behavior-par-un-developpeur/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MEF et PRISM</title>
		<link>http://blog.experida.fr/2010/07/27/mef-et-prism/</link>
		<comments>http://blog.experida.fr/2010/07/27/mef-et-prism/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 22:27:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[mef]]></category>
		<category><![CDATA[Prism]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/07/27/mef-et-prism/</guid>
		<description><![CDATA[D’un coté PRISM, est un Framework vous permettant de construire des applications flexibles, notamment via des modules capables d’évoluer indépendamment les uns des autres. Ils peuvent également communiquer entre eux mais de manière découplée. De l’autre MEF (Managed Extensibility Framework), est un Framework pour construire des applications extensibles. Il est capable de charger des plugins [...]]]></description>
			<content:encoded><![CDATA[<p>D’un coté PRISM, est un Framework vous permettant de construire des applications flexibles, notamment via des modules capables d’évoluer indépendamment les uns des autres. Ils peuvent également communiquer entre eux mais de manière découplée.</p>
<p>De l’autre MEF (Managed Extensibility Framework), est un Framework pour construire des applications extensibles. Il est capable de charger des plugins / DLL, depuis un endroit spécifique (assembly, répertoire &#8230;)  sans que ces derniers ne soient référencés dans le projet pour autant qu’ils respectent un contrat.</p>
<p>Dans sa version 4 alpha, Prism continue d’évoluer pour proposer:</p>
<ul>
<li>
<div>Une aide à l’implémentation du pattern MVVM</div>
</li>
<li>
<div>Navigation</div>
</li>
<li>
<div>Template / Code generation</div>
</li>
<li>
<div>Et une Gestion de la modularité avec MEF</div>
</li>
</ul>
<p>Pour plus d’informations voici le lien vers le blog de <a href="http://blogs.msdn.com/b/blaine/archive/2010/06/16/prism-4-0-plan-amp-drop-available-on-codeplex.aspx" target="_blank">Blaine Wastell</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/07/27/mef-et-prism/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF &#8211; Synchroniser des ListBox</title>
		<link>http://blog.experida.fr/2010/07/23/wpf-synchroniser-des-listbox-2/</link>
		<comments>http://blog.experida.fr/2010/07/23/wpf-synchroniser-des-listbox-2/#comments</comments>
		<pubDate>Fri, 23 Jul 2010 08:02:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[ScrollViewer]]></category>
		<category><![CDATA[Synchronization]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/?p=168</guid>
		<description><![CDATA[Dans certaines applications, on peut avoir le besoin d&#8217;afficher plusieurs contrôles de type ItemsControl et de les synchroniser dès qu&#8217;une scrollbar est déplacée. Pour faire simple, notre exemple va s&#8217;appuyer sur une ListBox. Créez une application WPF et ouvrez le code xaml de la fenêtre principale. Ajoutez ensuite deux ListBox avec dans chacune des données. [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Dans certaines applications, on peut avoir le besoin d&#8217;afficher plusieurs contrôles de type ItemsControl et de les synchroniser dès qu&#8217;une scrollbar est déplacée.</p>
<p align="justify">Pour faire simple, notre exemple va s&#8217;appuyer sur une ListBox.</p>
<p align="justify">Créez une application WPF et ouvrez le code xaml de la fenêtre principale. Ajoutez ensuite deux ListBox avec dans chacune des données. Peu importe le type des données que vous choisissez.&#160; Dans cette démo, nous allons ajouter des string en tant qu&#8217;item. Le type string est présent dans l&#8217;assembly mscorlib, il vous faut donc ajouter le namespace:</p>
<div align="justify">
<pre class="code"><span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">sys</span><span style="color: blue">=&quot;clr-namespace:System;assembly=mscorlib&quot;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<div align="justify"><span style="color: #ff0000; font-size: x-small"><span style="color: #ff0000; font-size: x-small"></span></span></div>
<p align="justify"><span style="color: #ff0000; font-size: x-small"><span style="color: #ff0000; font-size: x-small"></span></span></p>
<div align="justify"><span id="more-168"></span></div>
<p align="justify">&#160;</p>
<pre class="code">        <span style="color: blue">&lt;</span><span style="color: #a31515">StackPanel </span><span style="color: red">Orientation</span><span style="color: blue">=&quot;Horizontal&quot; </span><span style="color: red">VerticalAlignment</span><span style="color: blue">=&quot;Center&quot; </span><span style="color: red">HorizontalAlignment</span><span style="color: blue">=&quot;Center&quot;&gt;
            &lt;</span><span style="color: #a31515">ListBox </span><span style="color: red">Height</span><span style="color: blue">=&quot;50&quot;&gt;
                &lt;</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Alexandre</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Greg</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Patrice</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Amandine</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Alexandre</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Greg</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Patrice</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Amandine</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">ListBox </span><span style="color: red">Height</span><span style="color: blue">=&quot;50&quot; </span><span style="color: red">Margin</span><span style="color: blue">=&quot;10&quot;&gt;
                &lt;</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Appartement</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Appartement</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Maison</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Appartement</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Maison</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Appartement</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Appartement</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;</span><span style="color: #a31515">Maison</span><span style="color: blue">&lt;/</span><span style="color: #a31515">sys</span><span style="color: blue">:</span><span style="color: #a31515">String</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">ListBox.Items</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">ListBox</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">StackPanel</span><span style="color: blue">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<div align="justify"><span style="color: #a31515; font-size: x-small"><span style="color: #a31515; font-size: x-small"></span></p>
<p align="justify">
<p>  </span>Maintenant pour synchroniser nos deux listes, nous allons passer par des propriétés attachées. Nous avons que deux listbox ici, mais imaginez que vous souhaitiez synchroniser différents groupes de Listbox. J&#8217;insiste sur le mot groupe, car il va s&#8217;agir de notre première propriété attachée. Ajoutez une nouvelle classe ScrollSync dans votre solution. Pour créer rapidement votre propriété attachée vous pouvez utiliser le code snippet <strong>propa. </strong>Cette propriété sera attachée au ScrollViewer de la listbox qui représente une zone dans laquelle les éléments peuvent défiler.</div>
<div align="justify">
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">ScrollSync </span>: <span style="color: #2b91af">DependencyObject
  </span>{

      <span style="color: blue">public static string </span>GetGroupName(<span style="color: #2b91af">DependencyObject </span>obj)
      {
          <span style="color: blue">return </span>(<span style="color: blue">string</span>)obj.GetValue(GroupNameProperty);
      }

      <span style="color: blue">public static void </span>SetGroupName(<span style="color: #2b91af">DependencyObject </span>obj, <span style="color: blue">string </span>value)
      {
          obj.SetValue(GroupNameProperty, value);
      }

      <span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>GroupNameProperty =
          <span style="color: #2b91af">DependencyProperty</span>.RegisterAttached(<span style="color: #a31515">&quot;GroupName&quot;</span>,
          <span style="color: blue">typeof</span>(<span style="color: blue">string</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">ScrollSync</span>),
          <span style="color: blue">new </span><span style="color: #2b91af">UIPropertyMetadata</span>(<span style="color: blue">null</span>,
              <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedCallback</span>(OnGroupNameChanged)));

      <span style="color: blue">private static void
          </span>OnGroupNameChanged(<span style="color: #2b91af">DependencyObject </span>d,
          <span style="color: #2b91af">DependencyPropertyChangedEventArgs </span>e)
      { }

  }</pre>
</div>
<p align="justify">&#160;</p>
<p align="justify">Notez la présence d’une méthode Callback OnGroupNameChanged que nous allons modifier dans quelques instants après avoir créé:</p>
<ul>
<li>
<div align="justify">un dictionnaire pour stocker le ScrollViewer de nos Listbox participant à la synchonisation.</div>
</li>
<li>
<div align="justify">un dictionnaire pour stocker la Scroll Position horizontale d’un groupe</div>
</li>
<li>
<div align="justify">un dictionnaire pour stocker la Scroll Position verticale d’un groupe.</div>
</li>
</ul>
<div align="justify">
<pre class="code"><span style="color: blue">private static </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">ScrollViewer</span>, <span style="color: blue">string</span>&gt; scrollViewers = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">ScrollViewer</span>, <span style="color: blue">string</span>&gt;();
        <span style="color: blue">private static </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: blue">double</span>&gt; horizontalScrollOffsets = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: blue">double</span>&gt;();
        <span style="color: blue">private static </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: blue">double</span>&gt; verticalScrollOffsets = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: blue">string</span>, <span style="color: blue">double</span>&gt;();</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">&#160;</p>
<p align="justify">La première chose que nous allons faire dans le callback est de vérifier que la propriété attachée a bien été assignée à un élément de type ScrollViewer.</p>
<div align="justify">
<pre class="code"><span style="color: blue">var </span>scrollViewer = d <span style="color: blue">as </span><span style="color: #2b91af">ScrollViewer</span>;
<span style="color: blue">if </span>(scrollViewer != <span style="color: blue">null</span>)</pre>
</div>
<p align="justify">&#160;</p>
<p align="justify">Ensuite, via le paramètre DependencyPropertyChangedEventArgs&#160; et sa propriété NewValue, nous allons récupérer le nom de groupe qui a été attribué. On commence par vérifier que cette dernière ne vaut pas null, ce qui signifierait qu’on a pas de nom de groupe associé, puis on cherche si dans les dictionnaires HorizontalScrollOffset et VerticalScrollOffset, on a déjà ce nom engistré. Deux cas se présentent à nous.</p>
<p align="justify">1- Le nom est effectivement déjà enregistré, donc on utilise la méthode ScrollToHorizontalOffset ou ScrollToVerticalOffset pour placer la ScrollBar au même niveau que les autres du même groupe.</p>
<div align="justify">
<pre class="code"><span style="color: blue">if </span>(horizontalScrollOffsets.Keys.Contains((<span style="color: blue">string</span>)e.NewValue))
{
   scrollViewer.ScrollToHorizontalOffset(horizontalScrollOffsets[(<span style="color: blue">string</span>)e.NewValue]);
}</pre>
</div>
<ul>
<p align="justify">&#160;</p>
<p align="justify">2- Le groupe n’est pas encore identifié, on l’ajoute dans les deux dictionnaires précédents.</p>
<div align="justify">
<pre class="code">horizontalScrollOffsets.Add((<span style="color: blue">string</span>)e.NewValue, scrollViewer.HorizontalOffset);</pre>
</p></div>
<p>  <a href="http://11011.net/software/vspaste"></a></p>
<div align="justify">
<pre class="code">verticalScrollOffsets.Add((<span style="color: blue">string</span>)e.NewValue, scrollViewer.VerticalOffset);</pre>
</p></div>
<p>  <a href="http://11011.net/software/vspaste"></a></ul>
<ul>
<p align="justify">&#160;</p>
</ul>
<p align="justify">Afin de synchroniser les différentes ListBox dès qu’une ScrollBar est déplacée, nous allons maintenant nous abonner à l’évènement ScrollChanged du ScrollViewer et ajouter le ScrollViewer dans le Dictionnaire scrollViewers.</p>
<div align="justify">
<pre class="code"><span style="color: blue">if </span>(!scrollViewers.ContainsKey(scrollViewer))
                   {
                       scrollViewers.Add(scrollViewer, (<span style="color: blue">string</span>)e.NewValue);
                       scrollViewer.ScrollChanged += <span style="color: blue">new </span><span style="color: #2b91af">ScrollChangedEventHandler</span>(ScrollViewer_ScrollChanged);
                   }</pre>
</div>
<p align="justify">&#160;</p>
<p align="justify">Le Handler ScrollViewer_ScrollChanged met à notre disposition l’EventArgs ScrollChangedEventArgs dans lequel on peut savoir si un changement sur la ScrollBar horizontale ou la ScrollBar verticale a été effectué. Il suffit de tester que le VerticalChange ou le HorizontalChange est différent de 0. Dans ce cas on récupère le ScrollViewer&#160; via le sender et on appelle la méthode Scroll.</p>
<div align="justify">
<pre class="code"><span style="color: blue">private static void </span>ScrollViewer_ScrollChanged(<span style="color: blue">object </span>sender, <span style="color: #2b91af">ScrollChangedEventArgs </span>e)
       {
           <span style="color: blue">if </span>(e.VerticalChange != 0 || e.HorizontalChange != 0)
           {
               <span style="color: blue">var </span>changedScrollViewer = sender <span style="color: blue">as </span><span style="color: #2b91af">ScrollViewer</span>;
               Scroll(changedScrollViewer);
           }
       }</pre>
</div>
<p>&#160;</p>
<p>Dans cette méthode</p>
<ul>
<li>on récupère le groupe du scrollviewer</li>
<li>on met à jour le VerticalOffset et le HorizontalOffset</li>
<li>on parcours l’ensemble des scrollViewers enregistrés pour ce groupe et on applique la nouvelle position verticale / horizontale via la méthode ScrollToVerticalOffset / ScrollToHorizontalOffset.</li>
</ul>
<pre class="code"><span style="color: blue">private static void </span>Scroll(<span style="color: #2b91af">ScrollViewer </span>changedScrollViewer)
       {
           <span style="color: blue">var </span>group = scrollViewers[changedScrollViewer];
           verticalScrollOffsets[group] = changedScrollViewer.VerticalOffset;
           horizontalScrollOffsets[group] = changedScrollViewer.HorizontalOffset;

           <span style="color: blue">foreach </span>(<span style="color: blue">var </span>scrollViewer <span style="color: blue">in </span>scrollViewers.Where((s) =&gt; s.Value == group &amp;&amp; s.Key != changedScrollViewer))
           {
               <span style="color: blue">if </span>(scrollViewer.Key.VerticalOffset != changedScrollViewer.VerticalOffset)
               {
                   scrollViewer.Key.ScrollToVerticalOffset(changedScrollViewer.VerticalOffset);
               }

               <span style="color: blue">if </span>(scrollViewer.Key.HorizontalOffset != changedScrollViewer.HorizontalOffset)
               {
                   scrollViewer.Key.ScrollToHorizontalOffset(changedScrollViewer.HorizontalOffset);
               }
           }
       }</pre>
<p>&#160;</p>
<p>La dernière étape qu’il nous reste à voir est l’application de la propriété attachée pour chaque ScrollViewer des ListBox. Ouvrez le code xaml et définissez le style suivant:</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">ListBox.Style</span><span style="color: blue">&gt;
       &lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">x</span><span style="color: blue">:</span><span style="color: #a31515">Type </span><span style="color: red">ListBox</span><span style="color: blue">}&quot;&gt;
            &lt;</span><span style="color: #a31515">Style.Resources</span><span style="color: blue">&gt;
              &lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;ScrollViewer&quot;&gt;
                    &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;local:ScrollSync.ScrollGroupName&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;ScrollGroup&quot; /&gt;
              &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Style.Resources</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
 &lt;/</span><span style="color: #a31515">ListBox.Style</span><span style="color: blue">&gt;
</span></pre>
<p>&#160;</p>
<p>Téléchargez le code <a href="http://blog.experida.fr/wp-content/uploads/2010/07/code.zip" target="_blank">ici</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/07/23/wpf-synchroniser-des-listbox-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Silverlight &#8211; D&#233;veloppement d&#8217;un carrousel</title>
		<link>http://blog.experida.fr/2010/07/16/silverlight-4-e28093-developpement-de28099un-carrousel/</link>
		<comments>http://blog.experida.fr/2010/07/16/silverlight-4-e28093-developpement-de28099un-carrousel/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 16:47:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Carrousel]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/07/16/silverlight-4-e28093-developpement-de28099un-carrousel/</guid>
		<description><![CDATA[Dans ce billet, je vous propose de développer étape par étape un carrousel que vous pourrez facilement utiliser dans votre application silverlight. Pour y parvenir, commencez par ajouter un Custom Control WPF, vous devriez voir apparaître un fichier de code avec le nom que vous avez donné dans le wizard, ainsi qu’un fichier generic.xaml, contenant [...]]]></description>
			<content:encoded><![CDATA[<p>Dans ce billet, je vous propose de développer étape par étape un carrousel que vous pourrez facilement utiliser dans votre application silverlight.</p>
<p>Pour y parvenir, commencez par ajouter un Custom Control WPF, vous devriez voir apparaître un fichier de code avec le nom que vous avez donné dans le wizard, ainsi qu’un fichier generic.xaml, contenant les styles de notre contrôle.</p>
<p>Un carrousel est un contrôle contenant un ensemble d’objets. Pour la suite de ce billet définissons les termes suivants:</p>
<ul>
<li>
<div>Carousel: représente notre Custom Control, avec sa collection d’objets.</div>
</li>
<li>
<div>CarouselItem: représente un élément&#160; de notre carrousel.</div>
</li>
</ul>
<p> <span id="more-156"></span>Comme nous souhaitons travailler avec une collection de données, nous allons faire hériter notre contrôle de la classe ItemsControl. De cette manière, nous bénéficierons&#160; de propriétés et méthodes existantes.
</p>
<p>Ouvrez le fichier de code, supprimez l’héritage existant sur Control et remplacez le par ItemsControl</p>
<div>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">Carousel </span>: <span style="color: #2b91af">ItemsControl
</span>{
    <span style="color: blue">static </span>Carousel()
    {
        DefaultStyleKeyProperty.
            OverrideMetadata(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Carousel</span>),
            <span style="color: blue">new </span><span style="color: #2b91af">FrameworkPropertyMetadata</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Carousel</span>)));
    }
}</pre>
</div>
<p>Avant d’aller plus loin dans le code de notre contrôle, voici quelques points importants</p>
<ul>
<li>
<div>Un ItemsControl est un type de contrôle pouvant prendre en entrée une collection de différents objets comme une string, un rectangle&#8230;</div>
</li>
<li>
<div>Un UIElement ajouté en tant qu’Item du type ItemsControls est ajouté comme enfant du ItemsPanel représenté par un stackpanel par défaut.</div>
</li>
<li>
<div>Tout élément qui n’est pas un UIElement est wrappé dans un ContentPresenter</div>
</li>
</ul>
<p>Dans le cas de notre carrousel, nous allons devoir manipuler les différents éléments depuis le code. Afin de simplifier cette manipulation, nous allons demander au ItemContainerGenerator de nous créer un wrapper de type CarouselItem pour chaque Item</p>
<p>Commençons par ajouter une classe CarouselItem qui hérite de ContentControl. Le générateur de conteneur se chargera tout seul d’assigner le contrôle en tant que Content du CarouselItem.</p>
<div>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">CarouselItem </span>: <span style="color: #2b91af">ContentControl
   </span>{
        <span style="color: blue">public </span>CarouselItem()
       {
           <span style="color: blue">this</span>.DefaultStyleKey = <span style="color: blue">typeof</span>(<span style="color: #2b91af">CarouselItem</span>);
       }

   }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Maintenant que nous pouvons manipuler le type CarouselItem, modifions le contrôle Carousel de manière à ce que le générateur fasse ce que l’on vient de voir.</p>
<p>La première modification consiste à surcharger la méthode IsItemItsOwnContainerOverride qui permet d’indiquer si le contrôle passé est son propre conteneur. Dans notre cas le carrousel contiendra des rectangles. Comme on vient tout juste de voir que le conteneur devait être un CarouselItem,&#160; il nous suffit de faire un test de type.</p>
<div>
<pre class="code"><span style="color: blue">protected override bool </span>IsItemItsOwnContainerOverride(<span style="color: blue">object </span>item)
      {
          <span style="color: blue">return </span>item <span style="color: blue">is </span><span style="color: #2b91af">CarouselItem</span>;
      }</pre>
</div>
<p>Comme avec des Rectangles cette méthode retournera false, une seconde méthode que nous allons également surcharger est appelée juste après. Il s’agit de la méthode GetContainerForItemOverride. Nous lui disons simplement de créer un conteneur de type CarouselItem.</p>
<div>
<pre class="code"><span style="color: blue">protected override </span><span style="color: #2b91af">DependencyObject </span>GetContainerForItemOverride()
       {
           <span style="color: blue">return new </span><span style="color: #2b91af">CarouselItem</span>();
       }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans un carrousel les éléments ont une position bien spécifique. Afin de les placer simplement où l’on veut, nous allons remplacer le panel par défaut qui contient les Items par un Canvas avec lequel on pourra spécifier les coordonnées Left et Top de l’item. Nous allons également modifier le Template par défaut et ajouter un Grid nommé “PART_RootLayout” qui va nous servir de conteneur principal notamment pour centrer le carrousel.</p>
<p>Dans le generic.xaml qui est le fichier contenant les styles de notre contrôle, modifions la propriété ItemsPanel.</p>
<div>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;local:Carousel&quot;&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Width&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;800&quot;/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Height&quot; </span><span style="color: red">Value</span><span style="color: blue">=&quot;600&quot;/&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Template&quot;&gt;
            &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ControlTemplate </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;local:Carousel&quot;&gt;
                    &lt;</span><span style="color: #a31515">Grid
                        </span><span style="color: red">Background</span><span style="color: blue">=&quot;Red&quot;
                        </span><span style="color: red">Name</span><span style="color: blue">=&quot;PART_RootLayout&quot;
                        </span><span style="color: red">Width</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">TemplateBinding </span><span style="color: red">Width</span><span style="color: blue">}&quot;
                        </span><span style="color: red">Height</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">TemplateBinding </span><span style="color: red">Height</span><span style="color: blue">}&quot;&gt;
                        &lt;</span><span style="color: #a31515">ItemsPresenter</span><span style="color: blue">/&gt;
                    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">ControlTemplate</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;ItemsPanel&quot;&gt;
            &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
                    &lt;</span><span style="color: #a31515">Canvas </span><span style="color: blue">/&gt;
                &lt;/</span><span style="color: #a31515">ItemsPanelTemplate</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Notez au passage qu’on assigne une hauteur et largeur par défaut au contrôle. Si ces valeurs sont modifiées à partir des propriétés du contrôle, elles seront surchargées.</p>
<p>Retournons maintenant dans le code du contrôle. A présent faisons une surcharge de la méthode PrepareContainerForItemOverride, dont le but est comme le nom l’indique de préparer le conteneur pour afficher l’item correspondant.</p>
<div>
<pre class="code"><span style="color: blue">protected override
         void </span>PrepareContainerForItemOverride(<span style="color: #2b91af">DependencyObject </span>element,
         <span style="color: blue">object </span>item)
     {

         <span style="color: blue">base</span>.PrepareContainerForItemOverride(element, item);
     }</pre>
</div>
<p>Pour calculer la position d’un item, nous allons nous appuyer sur le cercle trigonométrique qui sera la base pour calculer la position d’un item à un instant t.</p>
<p>Considérons un cercle C de rayon 1 et de périmètre 2 PI. Pour notre exemple nous allons ajouter 4 éléments à notre ItemsControl.&#160; Nous voulons également que nos éléments soient placés de manière à ce qu’entre deux points l’arc (mesure en radian) soit équivalent.</p>
<p>Avant de modifier PrepareContainerForItemOverride, ajoutez une DependencyProperty Angle de type double à l’objet CarouselItem.</p>
<div>
<pre class="code"><span style="color: blue">public double </span>Angle
        {
            <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: blue">double</span>)GetValue(AngleProperty); }
            <span style="color: blue">set </span>{ SetValue(AngleProperty, <span style="color: blue">value</span>); }
        }

        <span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>AngleProperty =
            <span style="color: #2b91af">DependencyProperty</span>.Register(<span style="color: #a31515">&quot;Angle&quot;</span>,
            <span style="color: blue">typeof</span>(<span style="color: blue">double</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">CarouselItem</span>), <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(0.0));</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Maintenant dans la méthode PrepareContainer nous allons calculer l’angle de chaque item et insérer l’item dans une collection privée au contrôle pour le manipuler plus tard si besoin.</p>
<div>
<pre class="code"><span style="color: blue">int </span>preparedItem = 0;

       <span style="color: blue">protected override
           void </span>PrepareContainerForItemOverride(<span style="color: #2b91af">DependencyObject </span>element,
           <span style="color: blue">object </span>item)
       {
           <span style="color: #2b91af">CarouselItem </span>carouselItem = element <span style="color: blue">as </span><span style="color: #2b91af">CarouselItem</span>;
           <span style="color: blue">if </span>(carouselItem != <span style="color: blue">null</span>)
           {
               carouselItem.Angle = ((<span style="color: #2b91af">Math</span>.PI * 2) * preparedItem) /
                   Items.Count;
               preparedItem++;
               items.Add(carouselItem);
           }
           <span style="color: blue">base</span>.PrepareContainerForItemOverride(element, item);
       }</pre>
</div>
<p>Pour que la position des items soit recalculée régulièrement, nous avons à présent besoin d’un timer.&#160; Nous pourrions utiliser un DispatcherTimer, mais d’après ce site (<a title="http://blogs.silverlight.net/blogs/msnow/archive/2008/07/09/storyboard-versus-dispatchertimer-for-animation-and-game-loops.aspx" href="http://blogs.silverlight.net/blogs/msnow/archive/2008/07/09/storyboard-versus-dispatchertimer-for-animation-and-game-loops.aspx">http://blogs.silverlight.net/blogs/msnow/archive/2008/07/09/storyboard-versus-dispatchertimer-for-animation-and-game-loops.aspx</a>), l&#8217;utilisation d’une storyboard aurait quelques avantages.</p>
<p>Pour ajouter une storyboard, retournez dans le generic.xaml et au niveau du Part_RootLayout créez la en tant que ressource.</p>
<div>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">Grid  </span><span style="color: red">Background</span><span style="color: blue">=&quot;Red&quot;
        </span><span style="color: red">Name</span><span style="color: blue">=&quot;PART_RootLayout&quot;
        </span><span style="color: red">Width</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">TemplateBinding </span><span style="color: red">Width</span><span style="color: blue">}&quot;
        </span><span style="color: red">Height</span><span style="color: blue">=&quot;{</span><span style="color: #a31515">TemplateBinding </span><span style="color: red">Height</span><span style="color: blue">}&quot;&gt;
        &lt;</span><span style="color: #a31515">Grid.Resources</span><span style="color: blue">&gt;
               &lt;</span><span style="color: #a31515">Storyboard </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Key</span><span style="color: blue">=&quot;Timer&quot; </span><span style="color: red">Duration</span><span style="color: blue">=&quot;0&quot;
                             </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Timer&quot; /&gt;
        &lt;/</span><span style="color: #a31515">Grid.Resources</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">ItemsPresenter</span><span style="color: blue">/&gt;
 &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Pour récupérer&#160; et travailler avec cette ressource depuis le code de votre contrôle il vous suffit d’appeler la propriété ressource du PART_RootLayout et d’y passer en paramètre la Key de la storyboard. Pour cela deux choses à faire:</p>
<ul>
<li>
<div>Surcharger la méthode OnApplyTemplate</div>
</li>
<li>
<div>Récupérer les contrôles PART_RootLayout et la storyboard liée.</div>
</li>
</ul>
<div>
<pre class="code"><span style="color: blue">private </span><span style="color: #2b91af">Storyboard </span>timer;
<span style="color: blue">public override void </span>OnApplyTemplate()
{
    <span style="color: blue">base</span>.OnApplyTemplate();

    <span style="color: blue">this</span>.rootLayoutPart =
        GetTemplateChild(rootLayoutPartName)
            <span style="color: blue">as </span><span style="color: #2b91af">FrameworkElement</span>;
    <span style="color: blue">if </span>(<span style="color: blue">this</span>.rootLayoutPart == <span style="color: blue">null</span>)
        <span style="color: blue">throw new </span><span style="color: #2b91af">Exception</span>(<span style="color: #a31515">&quot;RootLayout introuvable&quot;</span>);

    <span style="color: blue">this</span>.timer = rootLayoutPart.Resources[<span style="color: #a31515">&quot;Timer&quot;</span>]
        <span style="color: blue">as </span><span style="color: #2b91af">Storyboard</span>;
    <span style="color: blue">if </span>(timer == <span style="color: blue">null</span>)
        <span style="color: blue">throw new </span><span style="color: #2b91af">Exception</span>(<span style="color: #a31515">&quot;Timer Storyboard est introuvable&quot;</span>);

    <span style="color: blue">this</span>.timer.Completed -= <span style="color: blue">new </span><span style="color: #2b91af">EventHandler</span>(timer_Completed);
    <span style="color: blue">this</span>.timer.Completed += <span style="color: blue">new </span><span style="color: #2b91af">EventHandler</span>(timer_Completed);
    <span style="color: blue">this</span>.timer.Begin();
}</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Une fois la storyboard récupérée, ajoutez un handler pour savoir quand elle se termine et démarrez la.</p>
<p>Avant de saisir le code dans la méthode timer_Completed, nous avons deux DependencyProperty à ajouter dans le code du contrôle Carrousel.</p>
<ul>
<li>
<div>Radius: en trigonométrie, les valeurs de Cosinus et Sinus sont comprises entre – 1 et 1. De manière à avoir un résultat plus visible, le Radius va nous permettre d’avoir un coefficient multiplicateur</div>
</li>
<li>
<div>Speed: permet de spécifier la mesure de l’arc entre un point A à l’instant t et ce même point à l’instant t+ 1.</div>
</li>
</ul>
<div>
<pre class="code"><span style="color: blue">public double </span>Radius
       {
           <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: blue">double</span>)GetValue(RadiusProperty); }
           <span style="color: blue">set </span>{ SetValue(RadiusProperty, <span style="color: blue">value</span>); }
       }

       <span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>RadiusProperty =
           <span style="color: #2b91af">DependencyProperty</span>.Register(<span style="color: #a31515">&quot;Radius&quot;</span>,
           <span style="color: blue">typeof</span>(<span style="color: blue">double</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">Carousel</span>),
           <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(200.0));

       <span style="color: blue">public double </span>Speed
       {
           <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: blue">double</span>)GetValue(SpeedProperty); }
           <span style="color: blue">set </span>{ SetValue(SpeedProperty, <span style="color: blue">value</span>); }
       }

       <span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>SpeedProperty =
           <span style="color: #2b91af">DependencyProperty</span>.Register(<span style="color: #a31515">&quot;Speed&quot;</span>,
           <span style="color: blue">typeof</span>(<span style="color: blue">double</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">Carousel</span>),
           <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(.0250));</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>La storyboard contient un timer qui ne tourne pas indéfiniment. La première chose que nous avons donc à faire est d’ajouter un <strong>timer.Begin()</strong> dans le handler <strong>timer_Completed.&#160; </strong></p>
<p>Maintenant il ne vous reste plus qu’à:</p>
<ul>
<li>
<div>parcourir la collection privée de CarouselItem</div>
</li>
<li>
<div>ajouter / soustraire (selon le sens de rotation) à l’angle courant la propriété Speed</div>
</li>
<li>
<div>calculer le cosinus pour l’axe des X et le sinus pour l’axe des Y de l’angle</div>
</li>
<li>
<div>positionner l’item par rapport au centre de son conteneur</div>
</li>
</ul>
<div>
<pre class="code"><span style="color: blue">void </span>timer_Completed(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
       {
           items.ForEach(c =&gt;
               {
                   c.Angle += Speed;

                   <span style="color: #2b91af">Canvas</span>.SetLeft(c,
                       <span style="color: #2b91af">Math</span>.Cos(c.Angle) * Radius
                        + (rootLayoutPart.ActualWidth / 2
                         - c.ActualWidth / 2));
                   <span style="color: #2b91af">Canvas</span>.SetTop(c,
                       <span style="color: #2b91af">Math</span>.Sin(c.Angle) * Radius
                        + (rootLayoutPart.ActualHeight / 2
                         - c.ActualHeight / 2));
               });

           timer.Begin();
       }</pre>
</div>
<p>Si vous lancez l&#8217;application vous constaterez que notre carrousel est pour l’instant vraiment plat.</p>
<p><strong>Une</strong> modification simple à apporter pour donner un effet de rotation 3D est de différencier le RadiusX, du RadiusY. Pour cela supprimez la propriété Radius et ajoutez les deux suivantes:</p>
<div>
<pre class="code"><span style="color: blue">public double </span>RadiusX
{
    <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: blue">double</span>)GetValue(RadiusXProperty); }
    <span style="color: blue">set </span>{ SetValue(RadiusXProperty, <span style="color: blue">value</span>); }
}

<span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>RadiusXProperty =
    <span style="color: #2b91af">DependencyProperty</span>.Register(<span style="color: #a31515">&quot;RadiusX&quot;</span>,
    <span style="color: blue">typeof</span>(<span style="color: blue">double</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">Carousel</span>),
    <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(150.0));

<span style="color: blue">public double </span>RadiusY
{
    <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: blue">double</span>)GetValue(RadiusYProperty); }
    <span style="color: blue">set </span>{ SetValue(RadiusYProperty, <span style="color: blue">value</span>); }
}

<span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>RadiusYProperty =
    <span style="color: #2b91af">DependencyProperty</span>.Register(<span style="color: #a31515">&quot;RadiusY&quot;</span>,
    <span style="color: blue">typeof</span>(<span style="color: blue">double</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">Carousel</span>),
    <span style="color: blue">new </span><span style="color: #2b91af">PropertyMetadata</span>(50.0));</pre>
</div>
<p>Puis dans le handler <strong>timer_Completed, </strong>modifiez le code de manière à utiliser le RadiusX avec le cosinus et le RadiusY avec le Sinus.</p>
<p><strong>Deuxième</strong> point sur le lequel on peut intervenir le ZIndex. Si on considère un carrousel 3D, les éléments qui sont plus loin de notre point de vue doivent apparaître derrière. Pour la valeur du ZIndex, on récupère la position selon l’axe Y en mettant une valeur positive ou négative sur le radiusY à l’instant t.</p>
<div>
<pre class="code"><span style="color: #2b91af">Point </span>position = <span style="color: blue">new </span><span style="color: #2b91af">Point</span>();
                   position.X = <span style="color: #2b91af">Math</span>.Cos(c.Angle) * RadiusX
                        + (rootLayoutPart.ActualWidth / 2
                         - c.ActualWidth / 2);
                   position.Y =  <span style="color: #2b91af">Math</span>.Sin(c.Angle) * RadiusY
                        + (rootLayoutPart.ActualHeight / 2
                         - c.ActualHeight / 2);

                   <span style="color: #2b91af">Canvas</span>.SetLeft(c, position.X);
                   <span style="color: #2b91af">Canvas</span>.SetTop(c, position.Y);

                   <span style="color: blue">if </span>(<span style="color: blue">this</span>.RadiusY &gt;= 0)
                       <span style="color: #2b91af">Canvas</span>.SetZIndex(c, -(<span style="color: blue">int</span>)position.Y);
                   <span style="color: blue">else
                       </span><span style="color: #2b91af">Canvas</span>.SetZIndex(c, (<span style="color: blue">int</span>)position.Y);</pre>
</div>
<p><strong>Troisième</strong> et dernier point que nous allons traiter dans cet exemple, le ScaleTransform. Comme on vient de le faire avec le Zindex, nous allons pouvoir jouer sur la taille de l’item en fonction de sa position dans le carrousel</p>
<p>Ouvrez à nouveau le fichier generic.xaml pour y définir le template du type CarouselItem et par la même occasion lui associer une ScaleTransform.</p>
<div>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">Style </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;local:CarouselItem&quot;&gt;
        &lt;</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">=&quot;Template&quot;&gt;
            &lt;</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
                &lt;</span><span style="color: #a31515">ControlTemplate </span><span style="color: red">TargetType</span><span style="color: blue">=&quot;local:CarouselItem&quot;&gt;
                    &lt;</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                        &lt;</span><span style="color: #a31515">ContentPresenter</span><span style="color: blue">/&gt;
                        &lt;</span><span style="color: #a31515">Grid.RenderTransform</span><span style="color: blue">&gt;
                                &lt;</span><span style="color: #a31515">ScaleTransform </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;ScaleTransform&quot;
                                                </span><span style="color: red">ScaleX</span><span style="color: blue">=&quot;1&quot;
                                                </span><span style="color: red">ScaleY</span><span style="color: blue">=&quot;1&quot;/&gt;
                        &lt;/</span><span style="color: #a31515">Grid.RenderTransform</span><span style="color: blue">&gt;
                    &lt;/</span><span style="color: #a31515">Grid</span><span style="color: blue">&gt;
                &lt;/</span><span style="color: #a31515">ControlTemplate</span><span style="color: blue">&gt;
            &lt;/</span><span style="color: #a31515">Setter.Value</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">Setter</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">Style</span><span style="color: blue">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans le Template nous ne faisons rien de particulier mise à part demander au Template de nous afficher le contenu via le <strong>ContentPresenter. </strong>Notez également la présence du ScaleTransform qui permet de dire que par défaut notre CarouselItem est à l’échelle 1 sur les deux axes.</p>
<p>Comme nous l’avions fait précédemment dans le contrôle Carousel pour récupérer le PART_RootLayout, nous surchargeons la méthode OnApplyTemplate de CarouselItem afin de récupérer le ScaleTransform, puis nous l’exposons via une propriété.</p>
<div>
<pre class="code"><span style="color: blue">public override void </span>OnApplyTemplate()
{
    <span style="color: blue">base</span>.OnApplyTemplate();

    ScaleTransform = GetTemplateChild(ScaleTransformName) <span style="color: blue">as </span><span style="color: #2b91af">ScaleTransform</span>;
}

<span style="color: blue">public </span><span style="color: #2b91af">ScaleTransform </span>ScaleTransform
{
    <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: #2b91af">ScaleTransform</span>)GetValue(ScaleTransformProperty); }
    <span style="color: blue">set </span>{ SetValue(ScaleTransformProperty, <span style="color: blue">value</span>); }
}

<span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>ScaleTransformProperty =
    <span style="color: #2b91af">DependencyProperty</span>.Register(<span style="color: #a31515">&quot;ScaleTransform&quot;</span>,
    <span style="color: blue">typeof</span>(<span style="color: #2b91af">ScaleTransform</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">CarouselItem</span>), <span style="color: blue">null</span>);</pre>
</div>
<p>Le ScaleTransform est en place dans le CarouselItem, nous pouvons maintenant modifier sa valeur en fonction de la position de l’item sur l’axe des Y.</p>
<div>
<pre class="code"><span style="color: blue">double </span>sinus = <span style="color: #2b91af">Math</span>.Sin(c.Angle);
                  <span style="color: blue">if </span>(sinus &lt; 0.5)
                      sinus = 0.5;

                  c.ScaleTransform.ScaleX = c.ScaleTransform.ScaleY = sinus ;</pre>
</div>
<p>Ce billet était une simple démo pour construire la base d’un carrousel. Vous pouvez facilement le faire évoluer avec les points suivants:</p>
<ul>
<li>
<div>Changer le sens de rotation (Speed) en fonction d’où se trouve la souris</div>
</li>
<li>
<div>Faire varier&#160; l’opacité</div>
</li>
<li>
<div>Rendre sélectionnable un item</div>
</li>
<li>
<div>&#8230;.</div>
</li>
</ul>
<p><span style="text-decoration: underline">Sources de ce billet:</span> <a href="http://blog.experida.fr/wp-content/uploads/2010/07/sources.zip" target="_blank">sources.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/07/16/silverlight-4-e28093-developpement-de28099un-carrousel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ReadOnly Dependency Property</title>
		<link>http://blog.experida.fr/2010/07/13/readonly-dependency-property/</link>
		<comments>http://blog.experida.fr/2010/07/13/readonly-dependency-property/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 21:19:23 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[ReadOnly DependencyProperty]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/07/13/readonly-dependency-property/</guid>
		<description><![CDATA[Dans le développement d’un Custom Control WPF ou Silverlight, on utilise régulièrement des DependencyProperty. Mais il peut également arriver que l’on veuille ajouter une ReadOnly DependencyProperty. Pourquoi vouloir créer ce type de propriété ? Un cas que l’on rencontre souvent est de vouloir rendre accessible une information sur un état particulier du contrôle. Or cette [...]]]></description>
			<content:encoded><![CDATA[<p align="justify">Dans le développement d’un Custom Control WPF ou Silverlight, on utilise régulièrement des DependencyProperty. Mais il peut également arriver que l’on veuille ajouter une ReadOnly DependencyProperty.</p>
<p align="justify">Pourquoi vouloir créer ce type de propriété ?</p>
<div align="justify"><span id="more-153"></span></div>
<p align="justify">Un cas que l’on rencontre souvent est de vouloir rendre accessible une information sur un état particulier du contrôle. Or cette information n’a pas besoin d’être modifiée depuis l’UI. Comme pour les DependencyProperty classiques, vous pouvez créer des Binding, ou bien encore les utiliser dans des triggers. La seule possibilité pour modifier sa valeur est de le faire depuis une méthode de la classe du contrôle.</p>
<p align="justify">
<p align="justify">Voyons maintenant comment l’écrire. Partons du principe que j’ai un contrôle nommé SlidingPanel qui veut donner comme information l’état de visibilité de la partie navigation.</p>
<p align="justify">D’habitude lorsque l’on créé une DependencyProperty, on utilise la méthode Register. Dans le cas présent la méthode à utiliser est la méthode RegisterReadOnly qui retourne un objet de type DependencyPropertyKey et non un DependencyProperty comme Register. Cet objet nous permet d’accéder à la donnée depuis notre classe.</p>
<div align="justify">
<pre class="code"><span style="color: blue">private static readonly </span><span style="color: #2b91af">DependencyPropertyKey </span>NavigationBarVisibilityKey =
    <span style="color: #2b91af">DependencyProperty</span>.RegisterReadOnly(<span style="color: #a31515">&quot;NavigationBarVisibility&quot;</span>,
    <span style="color: blue">typeof</span>(<span style="color: #2b91af">Visibility</span>),
    <span style="color: blue">typeof</span>(<span style="color: #2b91af">SlidingPanel</span>),
    <span style="color: blue">new </span><span style="color: #2b91af">FrameworkPropertyMetadata</span>(<span style="color: #2b91af">Visibility</span>.Collapsed));</pre>
</div>
<p align="justify">
  <br />Ensuite nous devons créer une DependencyProperty assignée depuis la propriété DependencyProperty de NavigationBarVisibilityKey. Il s’agit de la propriété readOnly accessible de l’extérieure de notre contrôle.</p>
<p></p>
<div align="justify">
<pre class="code"><span style="color: blue">public static readonly </span><span style="color: #2b91af">DependencyProperty </span>NavigationBarVisibilityProperty =
    NavigationBarVisibilityKey.DependencyProperty;</pre>
</div>
<p align="justify"><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Enfin ajoutons une propriété wrapper avec pour seule différence à une DependencyProperty classique le setter auquel on ajoute le mot clé private pour spécifier que le SetValue ne sera appelé que depuis le contrôle.</p>
<div align="justify">
<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">Visibility </span>NavigationBarVisibility
      {
          <span style="color: blue">get </span>{ <span style="color: blue">return </span>(<span style="color: #2b91af">Visibility</span>)GetValue(NavigationBarVisibilityProperty); }
          <span style="color: blue">private set </span>{ SetValue(NavigationBarVisibilityKey, <span style="color: blue">value</span>); }
      }</pre>
</div>
<p align="justify"><a href="http://11011.net/software/vspaste"></a></p>
<p align="justify">Et voilà le tour est joué.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/07/13/readonly-dependency-property/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qu&#8217;est-ce que PRISM</title>
		<link>http://blog.experida.fr/2010/07/07/quest-ce-que-prism/</link>
		<comments>http://blog.experida.fr/2010/07/07/quest-ce-que-prism/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 19:40:30 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[Prism]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/?p=147</guid>
		<description><![CDATA[Parmi les développeurs .NET qui travaillent sur des interfaces riches avec Silverlight ou WPF, on entend beaucoup parler de PRISM. Mais qu’est-ce que PRISM ? Certains diront qu’il s’agit d’un Framework permettant d’appliquer le pattern MVVM, d’autres qu’il permet de découper son application en modules. En effet PRISM nous permet bien de réaliser ces deux [...]]]></description>
			<content:encoded><![CDATA[<p>Parmi les développeurs .NET qui travaillent sur des interfaces riches avec Silverlight ou WPF, on entend beaucoup parler de PRISM.</p>
<p>Mais qu’est-ce que PRISM ?</p>
<p><span id="more-147"></span></p>
<p>Certains diront qu’il s’agit d’un Framework permettant d’appliquer le pattern MVVM, d’autres qu’il permet de découper son application en modules. En effet PRISM nous permet bien de réaliser ces deux opérations, mais c’est avant tout un ensemble d’outils qui  au travers de bonnes pratiques, donne la possibilité de construire des applications testables, maintenables et évolutives.</p>
<p>Si on s ‘en tient à quelques mots, avec PRISM vous pourrez:</p>
<ul>
<li>
<div><strong>Créer une application modulaire: </strong>vous avez la possibilité de découper votre application en différents modules qui peuvent évoluer chacun de leur côté. PRISM met à votre disposition un catalogue qui référence, l’ensemble des modules que contient l’application. Dll ou xap que vous soyez avec WPF ou Silverlight.</div>
</li>
<li>
<div><strong>Appliquer des régions: </strong>une région est un élément qui contient une vue indépendante des autres. Ainsi, vous pouvez avoir un ensemble de vues constituant votre interface, mais chacune est libre d’évoluer comme bon lui semble dans son module.</div>
</li>
<li>
<div><strong>Appliquer le pattern MVVM:</strong> le pattern MVVM, comme vous le savez permet de séparer les rôles à savoir d’un côté la vue et de l’autre le ViewModel / Presenter qui va se charger de fournir / adapter les  données pour la vue. De plus votre application est plus facilement testable. Pour communiquer avec le ViewModel, le pattern MVVM utilise les commandes. Si vous utilisez notamment Silverlight dans une version antérieur à la 4, cela peut s’avérer très utile, d’utiliser les propriétés attachées mises à disposition par PRISM pour faciliter la communication</div>
</li>
<li>
<div><strong>Mettre en place des modules faiblement couplés:  </strong>pour faire la résolution des services, vous pouvez vous appuyer sur Unity intégré directement dans PRISM. Définissez vos interfaces avec les implémentations correspondantes et enregistrez les dans le conteneur unity. Enfin pour communiquer entre les modules qui ne sont pas sensés se connaitre, ils peuvent communiquer via  une infrastructure qui s’appuie sur le pattern Publish / Subscribe.</div>
</li>
</ul>
<p> </p>
<p>Chacune de ces fonctionnalités est utilisable indépendamment des autres, c’est ça également la force de ce Framework</p>
<p>Si ce billet vous a donné le désir d’en savoir plus (ce que j’espère <img src='http://blog.experida.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ), voici quelques liens où vous pourrez trouver des informations complémentaires détaillées ainsi que des exemples.</p>
<ul>
<li>
<div><a href="http://msdn.microsoft.com/en-us/magazine/cc785479.aspx" target="_blank">Patterns For Building Composite Applications With WPF</a></div>
</li>
<li>
<div><a href="http://channel9.msdn.com/shows/Continuum/Prismv2/" target="_blank">Composite Application Guidance Pattern For Silverlight</a></div>
</li>
<li>
<div><a href="http://msdn.microsoft.com/en-us/library/dd490815.aspx" target="_blank">When To Use Guidance</a></div>
</li>
<li>
<div><a href="http://compositewpf.codeplex.com/wikipage?title=Learn%20Prism&amp;referringTitle=Home" target="_blank">Learn Prism</a></div>
</li>
<li>
<div><a href="http://compositewpf.codeplex.com/releases" target="_blank">Prism Download</a></div>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/07/07/quest-ce-que-prism/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4 &#8211; Export de donn&#233;es vers Excel</title>
		<link>http://blog.experida.fr/2010/06/28/silverlight-4-export-de-donnees-vers-excel/</link>
		<comments>http://blog.experida.fr/2010/06/28/silverlight-4-export-de-donnees-vers-excel/#comments</comments>
		<pubDate>Mon, 28 Jun 2010 20:56:09 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Export]]></category>
		<category><![CDATA[Out Of Browser]]></category>
		<category><![CDATA[Silverlight4]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/06/29/silverlight-4-export-de-donnees-vers-excel/</guid>
		<description><![CDATA[Il arrive souvent que dans une application business, l’utilisateur est besoin de faire une extraction des données notamment sous le format Excel. Silverlight nous donne la possibilité de le faire à condition d’être en mode out of browser. Avec Silverlight 3, nous avions la possibilité de faire fonctionner une application en mode out of browser. [...]]]></description>
			<content:encoded><![CDATA[<p>Il arrive souvent que dans une application business, l’utilisateur est besoin de faire une extraction des données notamment sous le format Excel. Silverlight nous donne la possibilité de le faire à condition d’être en mode out of browser.</p>
<p>Avec Silverlight 3, nous avions la possibilité de faire fonctionner une application en mode out of browser. Cela signifie qu’elle était détachée de son hôte de base, le navigateur, pour fonctionner comme une application installée sur le desktop.</p>
<p><span id="more-143"></span></p>
<p>Pour y arriver, il suffisait de faire clique droit sur le projet, puis sur l’onglet application, de cocher la case “Enable running application out of the browser”.</p>
<p><img title="image" src="http://www.silverlightshow.net/storage/users/emil/oob_OOB_option.png" alt="image" width="523" height="36" /></p>
<p>Parmi les différentes options de configuration de ce mode d’utilisation, Silverlight ajoute notamment la possibilité de préciser que l’application nécessite des droits élevés.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image5.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb9.png" border="0" alt="image" width="543" height="703" /></a></p>
<p>Ces droits sont justement nécessaires pour interagir avec les Interop COM et donc notamment Office. Toutes ces informations de droits, de taille de fenêtre sont stockées dans le fichier de déploiement AppManifest.xaml du fichier xap créé à la compilation de l’application.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image6.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb11.png" border="0" alt="image" width="471" height="148" /></a></p>
<p>Maintenant que les bases sont posées, commençons par créer une popup “ChildWindow”, dans laquelle nous indiquons à l’utilisateur qu’il doit procéder à l’installation de l’application pour l’utiliser.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image7.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb12.png" border="0" alt="image" width="365" height="135" /></a></p>
<p><span style="text-decoration: underline;">Code XAML correspondant:</span></p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">controls</span><span style="color: blue;">:</span><span style="color: #a31515;">ChildWindow </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Class</span><span style="color: blue;">="OutOfBrowserApp.SetupPage"
           </span><span style="color: red;">xmlns</span><span style="color: blue;">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           </span><span style="color: red;">xmlns</span><span style="color: blue;">:</span><span style="color: red;">x</span><span style="color: blue;">="http://schemas.microsoft.com/winfx/2006/xaml"
           </span><span style="color: red;">xmlns</span><span style="color: blue;">:</span><span style="color: red;">controls</span><span style="color: blue;">="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           </span><span style="color: red;">Width</span><span style="color: blue;">="400" </span><span style="color: red;">Height</span><span style="color: blue;">="300"
           </span><span style="color: red;">Title</span><span style="color: blue;">="SetupPage"&gt;
    &lt;</span><span style="color: #a31515;">Grid </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="LayoutRoot" </span><span style="color: red;">Margin</span><span style="color: blue;">="2"&gt;
        &lt;</span><span style="color: #a31515;">Grid.RowDefinitions</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">RowDefinition </span><span style="color: blue;">/&gt;
            &lt;</span><span style="color: #a31515;">RowDefinition </span><span style="color: red;">Height</span><span style="color: blue;">="Auto" /&gt;
        &lt;/</span><span style="color: #a31515;">Grid.RowDefinitions</span><span style="color: blue;">&gt;

        &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
            &lt;</span><span style="color: #a31515;">TextBlock
            </span><span style="color: red;">VerticalAlignment</span><span style="color: blue;">="Center"
            </span><span style="color: red;">HorizontalAlignment</span><span style="color: blue;">="Center"
            </span><span style="color: red;">Margin</span><span style="color: blue;">="10"
            </span><span style="color: red;">Text</span><span style="color: blue;">="Veuillez procéder à l'installation de l'application" /&gt;
            &lt;</span><span style="color: #a31515;">Button </span><span style="color: red;">Content</span><span style="color: blue;">="Installer" </span><span style="color: red;">Width</span><span style="color: blue;">="150" </span><span style="color: red;">Height</span><span style="color: blue;">="25" /&gt;
        &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Double cliquez sur le bouton pour ajouter un handler dans lequel on demande à l’application de s’installer.</p>
<pre class="code"><span style="color: blue;">private void </span>Button_Click(<span style="color: blue;">object </span>sender, <span style="color: #2b91af;">RoutedEventArgs </span>e)
{
    <span style="color: blue;">if </span>(<span style="color: #2b91af;">App</span>.Current.InstallState != <span style="color: #2b91af;">InstallState</span>.Installing
        &amp;&amp; <span style="color: #2b91af;">App</span>.Current.InstallState != <span style="color: #2b91af;">InstallState</span>.Installed)
    {
        <span style="color: #2b91af;">App</span>.Current.InstallStateChanged += (s, ev) =&gt;
        {
            <span style="color: blue;">if </span>(<span style="color: #2b91af;">App</span>.Current.InstallState == <span style="color: #2b91af;">InstallState</span>.Installed)
            {
                <span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Installation terminée"</span>);
            }
        };
        <span style="color: #2b91af;">App</span>.Current.Install();
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a>On commence par vérifier que l’application n’est pas déjà installée ou en cours d’installation, puis on lance la procédure. On s’abonne également à l’évènement InstallationStateChanged pour notifier l’utilisateur une fois l’installation terminée.</p>
<p>Comme nous souhaitons afficher cette fenêtre seulement lorsque  l’application n’est pas encore en mode out of browser, nous devons procéder à une vérification lors du chargement de la page principale.</p>
<pre class="code"><span style="color: blue;">if </span>(!<span style="color: #2b91af;">Application</span>.Current.IsRunningOutOfBrowser
    &amp;&amp; <span style="color: #2b91af;">Application</span>.Current.InstallState == <span style="color: #2b91af;">InstallState</span>.NotInstalled)
{
    <span style="color: #2b91af;">SetupPage </span>setup = <span style="color: blue;">new </span><span style="color: #2b91af;">SetupPage</span>();
    setup.Show();
}
<span style="color: blue;">else
</span>{
    <span style="color: #2b91af;">Application</span>.Current.CheckAndDownloadUpdateCompleted += (s, ev) =&gt;
        {
            <span style="color: blue;">if</span>(ev.UpdateAvailable)
                <span style="color: #2b91af;">MessageBox
                    </span>.Show(<span style="color: #a31515;">"Mise à jour de l'application effectuée,"
            </span>+<span style="color: #a31515;">"veuillez redémarrer l'application"</span>);
        };
    <span style="color: #2b91af;">Application</span>.Current.CheckAndDownloadUpdateAsync();
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Vous noterez au passage, la notification faite à l’utilisateur, si la présence d’une mise à jour est détectée puis installée.</p>
<p>Dans cette application démo, nous voulons exporter la liste des collaborateurs de l’entreprise vers un fichier Excel. Pour cela créons une classe Collaborateur avec trois propriétés Nom, Prénom et Age.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Collaborateur
</span>{
    <span style="color: blue;">public string </span>Nom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
    <span style="color: blue;">public string </span>Prenom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
    <span style="color: blue;">public int </span>Age { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a><br />
Du coté XAML, ajoutons, un DataGrid qui se trouve dans System.Windows.Controls.Data et un bouton pour réaliser l’export.</p>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
        &lt;</span><span style="color: #a31515;">data</span><span style="color: blue;">:</span><span style="color: #a31515;">DataGrid </span><span style="color: red;">AutoGenerateColumns</span><span style="color: blue;">="True"
                       </span><span style="color: red;">Name</span><span style="color: blue;">="CollaborateursListe" /&gt;
        &lt;</span><span style="color: #a31515;">Button  </span><span style="color: red;">Content</span><span style="color: blue;">="Exporter vers Excel" </span><span style="color: red;">Width</span><span style="color: blue;">="150"/&gt;
    &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans le code behind, créez une liste de collaborateurs et assignez là au DataGrid.</p>
<pre class="code"><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Collaborateur</span>&gt; collaborateurs = <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Collaborateur</span>&gt;() {
                <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur</span>{Nom=<span style="color: #a31515;">"Arnaudet"</span>,Prenom=<span style="color: #a31515;">"Alexandre"</span>,Age=25},
                <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur</span>{Nom=<span style="color: #a31515;">"MonNom"</span>,Prenom=<span style="color: #a31515;">"MonPrenom"</span>, Age=26}
            };

            <span style="color: blue;">this</span>.CollaborateursListe.ItemsSource = collaborateurs;</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><strong>Rappel: vous avez la possibilité d’utiliser le pattern </strong><a href="http://blog.experida.fr/2010/05/15/mise-en-place-du-pattern-mvvm-unity-dans-une-application-wpf/" target="_blank"><strong>MVVVM</strong></a><strong>, afin de bien séparer l’UI et la logique business.</strong></p>
<p>En démarrant l’application depuis votre bureau vous devriez maintenant avoir un écran avec la liste des collaborateurs qui s’affiche.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image8.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb13.png" border="0" alt="image" width="536" height="190" /></a> </p>
<p>Afin de procéder à l’export, commencez par ajouter un handler lié au bouton d’export, puis mettez le code suivant que nous allons détailler.</p>
<pre class="code"><span style="color: blue;">if </span>(<span style="color: #2b91af;">AutomationFactory</span>.IsAvailable)
          {
              <span style="color: blue;">dynamic </span>excel = <span style="color: #2b91af;">AutomationFactory
                  </span>.CreateObject(<span style="color: #a31515;">"Excel.Application"</span>);
              <span style="color: blue;">dynamic </span>workbook = excel.workbooks;
              workbook.Add();
              <span style="color: blue;">dynamic </span>sheet = excel.ActiveSheet;

              excel.Visible = <span style="color: blue;">true</span>;

              <span style="color: blue;">dynamic </span>cell = <span style="color: blue;">null</span>;
              <span style="color: blue;">int </span>i = 1;

              <span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Collaborateur</span>&gt; collaborateurs =
                  <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Collaborateur</span>&gt;
                  (CollaborateursListe.ItemsSource.OfType&lt;<span style="color: #2b91af;">Collaborateur</span>&gt;());
              collaborateurs.ForEach(c =&gt;
                  {
                      cell = sheet.Cells[i, 1];
                      cell.Value = c.Nom;

                      cell = sheet.Cells[i, 2];
                      cell.Value = c.Prenom;

                      cell = sheet.Cells[i,3];
                      cell.Value = c.Age;

                      i++;
                  });

              <span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Export terminé"</span>);
          }</pre>
<p>Première chose que l’on remarque, le mot Automation. L’automation permet à une application d’exposer des objets pour que ceux-ci soient utilisés par une application tierce, ou bien d’accéder à des objets mis à disposition par une autre application. Ils sont exposés via un serveur d’automation au travers d’interfaces COM.</p>
<p>AutomationFactory est l’entité permettant de savoir si le serveur est disponible. Cependant attention vous devez avoir des droits élevés pour y parvenir, d’où le début de ce billet.</p>
<p>Pour créer un objet, vous devez simplement via AutomationFactory, utiliser la méthode CreateObject qui prend en paramètre un progID. Ce progID est déterminé par l’application à laquelle on veut accéder. Il s’agit dans notre cas de “Excel.Application”. De la même manière vous avez “Outlook.Application” et “Word.Application” en ce qui concerne Office. Ensuite il ne vous reste plus qu’à créer un classeur et d’y récupérer la feuille active pour y insérer vos données.</p>
<p>Dernier point qu’il vous reste à faire. Parcourir le datagrid pour créer les cellules et y afficher vos données.</p>
<p>Vous noterez également l’utilisation du mot clé dynamic arrivé avec C# 4. Vous pourrez trouver plus d’informations concernant ce sujet à cette <a href="http://msdn.microsoft.com/en-us/library/dd264736.aspx" target="_blank">adresse</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/06/28/silverlight-4-export-de-donnees-vers-excel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF: les styles et la propri&#233;t&#233; BasedOn</title>
		<link>http://blog.experida.fr/2010/06/17/wpf-les-styles-et-la-proprit-basedon/</link>
		<comments>http://blog.experida.fr/2010/06/17/wpf-les-styles-et-la-proprit-basedon/#comments</comments>
		<pubDate>Thu, 17 Jun 2010 21:19:34 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[BasedOn]]></category>
		<category><![CDATA[Style]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/06/17/wpf-les-styles-et-la-proprit-basedon/</guid>
		<description><![CDATA[Comme vous le savez, WPF donne aux développeurs la possibilité d’améliorer l’aspect des contrôles via des Styles. Mais connaissez-vous la propriété BasedOn de l’élément Style. Au même titre que vous faites de l’héritage graphique avec des css, la propriété BasedOn permet d’hériter d’un autre style créé en XAML dans votre application. Prenons un exemple. Je [...]]]></description>
			<content:encoded><![CDATA[<p>Comme vous le savez, WPF donne aux développeurs la possibilité d’améliorer l’aspect des contrôles via des Styles. Mais connaissez-vous la propriété BasedOn de l’élément Style.</p>
<p>Au même titre que vous faites de l’héritage graphique avec des css, la propriété BasedOn permet d’hériter d’un autre style créé en XAML dans votre application.</p>
<p><span id="more-114"></span></p>
<p>Prenons un exemple.</p>
<p>Je souhaite que tous les boutons de mon application soient noirs avec une police blanche. Comme je suis quelqu’un de fainéant, je ne veux pas passer après chacun de mes boutons pour leur attribuer ce style de base. Je ne vais donc pas renseigner la propriété Key.</p>
<div>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">Style </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">Button</span><span style="color: blue;">}"&gt;
                &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Foreground" </span><span style="color: red;">Value</span><span style="color: blue;">="#FFFFFF"/&gt;
                &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Background" </span><span style="color: red;">Value</span><span style="color: blue;">="#000000" /&gt;
            &lt;/</span><span style="color: #a31515;">Style</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles66D23/image[3].png"><img style="display: inline; border: 0px;" title="image_thumb[10]" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb101.png" border="0" alt="image_thumb[10]" width="244" height="43" /></a></p>
<p>Maintenant que ce style est créé, j’ai besoin d’un bouton nécessitant en plus du style précédent que la police soit en gras. C’est là qu’entre en jeu la propriété BasedOn.</p>
<div>
<pre class="code">  <span style="color: blue;">&lt;</span><span style="color: #a31515;">Style </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="Gras" </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">Button</span><span style="color: blue;">}"
           </span><span style="color: red;">BasedOn</span><span style="color: blue;">="{</span><span style="color: #a31515;">StaticResource </span><span style="color: blue;">{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">Button</span><span style="color: blue;">}}"&gt;
       &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="FontWeight" </span><span style="color: red;">Value</span><span style="color: blue;">="Bold"/&gt;
  &lt;/</span><span style="color: #a31515;">Style</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Cette fois, on a la propriété Key sur notre style pour l’assigner à un bouton en particulier. Le TargetType est toujours identique puisque nous sommes toujours sur la définition d’un bouton et nous avons la fameuse propriété BasedOn qui indique ici que le bouton avec le style Gras hérite également du style de base donné à tous les bouttons.</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles66D23/image[7].png"><img style="display: inline; border: 0px;" title="image_thumb[19]" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb19.png" border="0" alt="image_thumb[19]" width="244" height="81" /></a></p>
<p>Enfin créons un dernier style afin de montrer que l’on peut écraser le style d’une propriété sans pour autant altérer le reste.</p>
<div>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">Style </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="Rouge" </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">Button</span><span style="color: blue;">}"
                   </span><span style="color: red;">BasedOn</span><span style="color: blue;">="{</span><span style="color: #a31515;">StaticResource </span><span style="color: red;">Gras</span><span style="color: blue;">}"&gt;
         &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Background" </span><span style="color: red;">Value</span><span style="color: blue;">="red"/&gt;
 &lt;/</span><span style="color: #a31515;">Style</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles66D23/image[11].png"><img style="display: inline; border: 0px;" title="image_thumb[24]" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb24.png" border="0" alt="image_thumb[24]" width="244" height="109" /></a></p>
<p>Comme vous pouvez le constater, via la propriété BasedOn on voit clairement que le dernier style hérite du style Gras qui lui même hérite du style commun aux boutons. La seule différence vient de la propriété Background, que nous avons surchargée dans ce style pour passer du noir au rouge.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/06/17/wpf-les-styles-et-la-proprit-basedon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Valider les donn&#233;es avec Silverlight</title>
		<link>http://blog.experida.fr/2010/06/13/valider-les-donnes-avec-silverlight/</link>
		<comments>http://blog.experida.fr/2010/06/13/valider-les-donnes-avec-silverlight/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 16:48:45 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[validation des données]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/06/13/valider-les-donnes-avec-silverlight/</guid>
		<description><![CDATA[Lorsque vous développez une application, il est important de s&#8217;assurer que les données présentes dans les objets sont correctes avant leur stockage. Il existe aujourd’hui différentes possibilités pour faire valider les données, selon que vous utilisez la version 3 ou 4 du Framework. Cependant pour y parvenir il y a quelques étapes à suivre, car [...]]]></description>
			<content:encoded><![CDATA[<p>Lorsque vous développez une application, il est important de s&#8217;assurer que les données présentes dans les objets sont correctes avant leur stockage.</p>
<p>Il existe aujourd’hui différentes possibilités pour faire valider les données, selon que vous utilisez la version 3 ou 4 du Framework.</p>
<p>Cependant pour y parvenir il y a quelques étapes à suivre, car par défaut, l’UI ne vous affichera pas de message d’erreur si la donnée source n’est pas correcte. Quand je dis “correcte”, il peut aussi bien s’agir d’un format de la donnée, que d’une valeur non possible selon une règle business.</p>
<p><span id="more-109"></span></p>
<p>Pour mettre en avant les différents cas, commençons par créer une classe Collaborateur avec simplement trois propriétés Nom / Age / DateEmbauche</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Collaborateur </span>: <span style="color: #2b91af;">INotifyPropertyChanged
       </span>{
           <span style="color: blue;">private string </span>nom;
           <span style="color: blue;">public string </span>Nom
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>nom; }
               <span style="color: blue;">set
               </span>{
                   <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= nom)
                   {
                       nom = <span style="color: blue;">value</span>;
                       OnNotify(<span style="color: #a31515;">"Nom"</span>);
                   }
               }
           }

           <span style="color: blue;">private int </span>age;
           <span style="color: blue;">public int </span>Age
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>age; }
               <span style="color: blue;">set
               </span>{
                   <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= age)
                   {
                       age = <span style="color: blue;">value</span>;
                       OnNotify(<span style="color: #a31515;">"Age"</span>);
                   }
               }
           }

           <span style="color: blue;">private </span><span style="color: #2b91af;">DateTime </span>dateEmbauche;
           <span style="color: blue;">public </span><span style="color: #2b91af;">DateTime </span>DateEmbauche
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>dateEmbauche; }
               <span style="color: blue;">set
               </span>{
                   <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= dateEmbauche)
                   {
                       dateEmbauche = <span style="color: blue;">value</span>;
                       OnNotify(<span style="color: #a31515;">"DateEmbauche"</span>);
                   }
               }
           }

           <span style="color: blue;">private void </span>OnNotify(<span style="color: blue;">string </span>name)
           {
               <span style="color: blue;">if </span>(!<span style="color: blue;">string</span>.IsNullOrEmpty(name) &amp;&amp; PropertyChanged != <span style="color: blue;">null</span>)
                   PropertyChanged(<span style="color: blue;">this</span>, <span style="color: blue;">new </span><span style="color: #2b91af;">PropertyChangedEventArgs</span>(name));
           }

           <span style="color: blue;">public event </span><span style="color: #2b91af;">PropertyChangedEventHandler </span>PropertyChanged;
       }</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Puis assignez au DataContext de la Vue une instance de cette classe.</p>
<pre class="code"><span style="color: blue;">this</span>.DataContext = <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur
            </span>{
                Nom = <span style="color: #a31515;">"Alexandre"</span>,
                Age = 25,
                DateEmbauche = <span style="color: blue;">new </span><span style="color: #2b91af;">DateTime</span>(2008, 4, 12)
            };</pre>
<p>Maintenant du côté de la vue, ajoutons trois contrôles TextBox avec lesquels on fait le binding sur le DataContext et donc sur l’entité Collaborateur.</p>
<pre class="code">    <span style="color: blue;">&lt;</span><span style="color: #a31515;">Grid </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="LayoutRoot" </span><span style="color: red;">Background</span><span style="color: blue;">="White"&gt;
        &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
            &lt;</span><span style="color: #a31515;">TextBox </span><span style="color: red;">Width</span><span style="color: blue;">="200" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Nom</span><span style="color: blue;">,</span><span style="color: red;">Mode</span><span style="color: blue;">=TwoWay}"/&gt;
            &lt;</span><span style="color: #a31515;">TextBox </span><span style="color: red;">Width</span><span style="color: blue;">="200" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Age</span><span style="color: blue;">,</span><span style="color: red;">Mode</span><span style="color: blue;">=TwoWay}"/&gt;
            &lt;</span><span style="color: #a31515;">TextBox </span><span style="color: red;">Width</span><span style="color: blue;">="200" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">DateEmbauche</span><span style="color: blue;">,</span><span style="color: red;">Mode</span><span style="color: blue;">=TwoWay}"/&gt;
        &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">Grid</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans cet état, si vous démarrez l’application et tentez de changer par exemple la date d’embauche en une date non valide, vous n’aurez aucune erreur qui apparaît à l’écran.</p>
<p>La première méthode pour remonter l’information est apparue avec la version 3. Elle consiste à lever une exception dans le setter de la propriété concernée.</p>
<p>Pour dire à l’objet Binding d’afficher l’exception, il faut d’abord ajouter le ValidatesOnExceptions à true au niveau du Binding sur la date d’embauche dans le code XAML. Cette valeur est par défaut à false.</p>
<p>En interne si une erreur est détectée, le moteur de binding créé un objet ValidationError et l’ajoute à la collection Validation.Errors de l’objet bindé. La propriété HasError de l’objet validation passe alors à true.  Le contrôle textBox depuis son template, va s’appuyer sur cette propriété HasError pour afficher le message.</p>
<p><span style="color: blue;">&lt;</span><span style="color: #a31515;">TextBox </span><span style="color: red;">Width</span><span style="color: blue;">=&#8221;200&#8243;</span><span style="color: red;">Text</span><span style="color: blue;">=&#8221;{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Age</span><span style="color: blue;">,</span><span style="color: red;">ValidatesOnExceptions</span><span style="color: blue;">=True}&#8221;/&gt;</p>
<p></span></p>
<p>Vous devriez maintenant avoir le message suivant qui s’affiche</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles98E581/image[5].png"><img style="display: inline; border: 0px;" title="image_thumb[7]" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb71.png" border="0" alt="image_thumb[7]" width="570" height="127" /></a> </p>
<p>On voit clairement qu’on a ici une erreur remontée par le TypeConverter. De la même manière on peut lever une exception sur l’âge. Pour cela, rendons-nous dans la définition de l’entité et ajoutons une règle.</p>
<pre class="code"><span style="color: blue;">private int </span>age;
         <span style="color: blue;">public int </span>Age
         {
             <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>age; }
             <span style="color: blue;">set
             </span>{
                 <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= age)
                 {
                     <span style="color: blue;">if </span>(<span style="color: blue;">value </span>&lt; 18)
                         <span style="color: blue;">throw new
                             </span><span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Tu dois avoir au moins 18 ans"</span>);
                     age = <span style="color: blue;">value</span>;
                     OnNotify(<span style="color: #a31515;">"Age"</span>);
                 }
             }
         }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Si maintenant, vous mettez un âge inférieur à 18 ans,  un message pour l’âge doit également apparaître.</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles98E581/image[21].png"><img style="display: inline; border: 0px;" title="image_thumb[25]" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb25.png" border="0" alt="image_thumb[25]" width="536" height="212" /></a></p>
<p>Notez au passage la présence d’un ValidationSummary qui a pour but de centraliser les différentes erreurs. Si vous souhaitez également l’utiliser, vous devez ajouter une référence sur System.Windows.Controls.Data.Input et également la propriété NotifyOnValidationError=true au niveau de la propriété bindée. Ceci aura pour effet de déclencher automatiquement l’évènement BindingValidationError auquel le ValidationSummary est attaché.</p>
<p>La deuxième solution qui est plus élégante que de lever une exception pour chaque validation, s’appuie sur l’interface IDataErrorInfo.  Cette interface nécessite l&#8217;’utilisation de Silverlight 4. Elle est constituée de deux propriétés et est particulièrement utile lorsque l’on a des règles business de validation.</p>
<ul>
<li>
<div>Error: qui permet de récupérer une erreur sur l’objet</div>
</li>
<li>
<div>this[string columnName]: qui retourne un message d’erreur spécifique à une propriété de l’objet</div>
</li>
</ul>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IDataErrorInfo
   </span>{
       <span style="color: blue;">string </span>Error { <span style="color: blue;">get</span>; }<span style="color: green;">
       </span><span style="color: blue;">string this</span>[<span style="color: blue;">string </span>columnName] { <span style="color: blue;">get</span>; }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Reprenons l’entité Collaborateur pour la mettre à jour avec cette interface.</p>
<pre class="code"><span style="color: blue;">public string </span>Error
          {
              <span style="color: blue;">get </span>{ <span style="color: blue;">return </span><span style="color: #a31515;">"Erreur dans la validation
                  </span>de l<span style="color: #a31515;">'objet collaborateur"; }
          </span>}

          <span style="color: blue;">public string this</span>[<span style="color: blue;">string </span>columnName]
          {
              <span style="color: blue;">get
              </span>{
                  <span style="color: blue;">string </span>error = <span style="color: blue;">null</span>;

                  <span style="color: blue;">switch </span>(columnName)
                  {
                      <span style="color: blue;">case </span><span style="color: #a31515;">"Age"</span>:
                          <span style="color: blue;">if </span>(Age &lt; 18)
                          {
                              error = <span style="color: #a31515;">"Tu dois avoir au moin 18 ans"</span>;
                          }
                          <span style="color: blue;">break</span>;
                  }
                  <span style="color: blue;">return </span>(error);
              }
          }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Au niveau du code XAML, il vous faut ajouter la propriété ValidatesOnDataErrors et la mettre à true</p>
<pre class="code">   <span style="color: blue;">&lt;</span><span style="color: #a31515;">TextBox </span><span style="color: red;">Width</span><span style="color: blue;">="200" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Age</span><span style="color: blue;">,</span><span style="color: red;">Mode</span><span style="color: blue;">=TwoWay,
        </span><span style="color: red;">ValidatesOnDataErrors</span><span style="color: blue;">=True,</span><span style="color: red;">NotifyOnValidationError</span><span style="color: blue;">=True}"/&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Comme pour la solution précédente, l’objet Binding sait que quand il y a un message d’erreur en retour de l’interface IDataErrorInfo, il doit créer un objet ValidationError.</p>
<p>A noter:</p>
<ul>
<li>
<div>Cette interface est déjà utilisée en WindowsForms et WPF, vous pouvez donc réutiliser les mêmes entités avec Silverlight 4.</div>
</li>
<li>
<div>Il s’agit d’un modèle synchrone, donc attention de pas avoir de règles de validation trop lourdes, sinon utilisez la dernière solution que nous allons voir d’ici quelques lignes.</div>
</li>
<li>
<div>L’interface ne retourne qu’un message par propriété de type string</div>
</li>
</ul>
<p> </p>
<p>Enfin la dernière solution consiste à utiliser INotifyDataErrorInfo. Préférez cette interface pour tout nouveau développement.</p>
<p><span style="text-decoration: underline;">Avantages:</span></p>
<ul>
<li>
<div>Elle permet d’appliquer des règles de validation de manière asynchrone.</div>
</li>
<li>
<div>Supporte des objets d’erreur personnalisés</div>
</li>
<li>
<div>Peut retourner plusieurs erreurs pour une propriété</div>
</li>
<li>
<div>Depuis une propriété vous pouvez vérifier la validation d’une seconde</div>
</li>
</ul>
<p><span style="text-decoration: underline;">Description de l’interface:</span></p>
<ul>
<li>
<div>HasError indique si une erreur existe dans l’entité</div>
</li>
<li>
<div>ErrorsChanged est un évènement appelé dès qu’une modification est apportée pour une erreur liée à une propriété ou à l’objet directement.</div>
</li>
<li>
<div>GetErrors récupère les erreurs pour une propriété.</div>
</li>
</ul>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">INotifyDataErrorInfo
   </span>{
      <span style="color: blue;">bool </span>HasErrors { <span style="color: blue;">get</span>; }

     <span style="color: green;"> </span><span style="color: blue;">event </span><span style="color: #2b91af;">EventHandler</span>&lt;<span style="color: #2b91af;">DataErrorsChangedEventArgs</span>&gt; ErrorsChanged;

      <span style="color: #2b91af;">IEnumerable </span>GetErrors(<span style="color: blue;">string </span>propertyName);
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Encore une fois apportons quelques modifications à notre classe collaborateur pour implémenter cette nouvelle interface</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Collaborateur </span>: <span style="color: #2b91af;">INotifyPropertyChanged</span>, <span style="color: #2b91af;">INotifyDataErrorInfo
       </span>{
           <span style="color: blue;">const string </span>DebutNomErreur = <span style="color: #a31515;">"Le nom doit commencer par un A"</span>;
           <span style="color: blue;">const string </span>FinNomErreur = <span style="color: #a31515;">"Le nom doit se terminer par un E"</span>;

           <span style="color: blue;">private string </span>nom;
           <span style="color: blue;">public string </span>Nom
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>nom; }
               <span style="color: blue;">set
               </span>{
                   <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= nom)
                   {

                       <span style="color: blue;">if </span>(!<span style="color: blue;">value</span>.ToLower().StartsWith(<span style="color: #a31515;">"a"</span>))
                           AddError(<span style="color: #a31515;">"Nom"</span>, DebutNomErreur);
                       <span style="color: blue;">else
                           </span>RemoveError(<span style="color: #a31515;">"Nom"</span>, DebutNomErreur);

                       <span style="color: blue;">if </span>(!<span style="color: blue;">value</span>.ToLower().EndsWith(<span style="color: #a31515;">"e"</span>))
                           AddError(<span style="color: #a31515;">"Nom"</span>, FinNomErreur);
                       <span style="color: blue;">else
                           </span>RemoveError(<span style="color: #a31515;">"Nom"</span>, FinNomErreur);

                       nom = <span style="color: blue;">value</span>;
                       OnNotify(<span style="color: #a31515;">"Nom"</span>);
                   }
               }
           }

           <span style="color: blue;">const string </span>AgeError = <span style="color: #a31515;">"Tu dois avoir au moins 18 ans"</span>;

           <span style="color: blue;">private int </span>age;
           <span style="color: blue;">public int </span>Age
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>age; }
               <span style="color: blue;">set
               </span>{
                   <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= age)
                   {
                       <span style="color: blue;">if </span>(<span style="color: blue;">value </span>&lt; 18)
                           AddError(<span style="color: #a31515;">"Age"</span>, AgeError);
                       <span style="color: blue;">else
                           </span>RemoveError(<span style="color: #a31515;">"Age"</span>, AgeError);

                       age = <span style="color: blue;">value</span>;
                       OnNotify(<span style="color: #a31515;">"Age"</span>);
                   }
               }
           }

           <span style="color: blue;">private </span><span style="color: #2b91af;">DateTime </span>dateEmbauche;
           <span style="color: blue;">public </span><span style="color: #2b91af;">DateTime </span>DateEmbauche
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>dateEmbauche; }
               <span style="color: blue;">set
               </span>{
                   <span style="color: blue;">if </span>(<span style="color: blue;">value </span>!= dateEmbauche)
                   {
                       dateEmbauche = <span style="color: blue;">value</span>;
                       OnNotify(<span style="color: #a31515;">"DateEmbauche"</span>);
                   }
               }
           }

           <span style="color: blue;">private void </span>OnNotify(<span style="color: blue;">string </span>name)
           {
               <span style="color: blue;">if </span>(!<span style="color: blue;">string</span>.IsNullOrEmpty(name) &amp;&amp; PropertyChanged != <span style="color: blue;">null</span>)
                   PropertyChanged(<span style="color: blue;">this</span>, <span style="color: blue;">new </span><span style="color: #2b91af;">PropertyChangedEventArgs</span>(name));
           }

           <span style="color: blue;">public event </span><span style="color: #2b91af;">PropertyChangedEventHandler </span>PropertyChanged;

           <span style="color: blue;">public event </span><span style="color: #2b91af;">EventHandler</span>&lt;<span style="color: #2b91af;">DataErrorsChangedEventArgs</span>&gt;
               ErrorsChanged;

           <span style="color: blue;">public </span>System.Collections.<span style="color: #2b91af;">IEnumerable
               </span>GetErrors(<span style="color: blue;">string </span>propertyName)
           {
               <span style="color: blue;">if </span>(!errors.ContainsKey(propertyName))
                   <span style="color: blue;">return null</span>;

               <span style="color: blue;">return </span>errors[propertyName];
           }

           <span style="color: blue;">public bool </span>HasErrors
           {
               <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>errors.Count &gt; 0; }

           }

           <span style="color: blue;">private </span><span style="color: #2b91af;">Dictionary</span>&lt;<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">String</span>&gt;&gt; errors
               = <span style="color: blue;">new </span><span style="color: #2b91af;">Dictionary</span>&lt;<span style="color: blue;">string</span>, <span style="color: #2b91af;">List</span>&lt;<span style="color: blue;">string</span>&gt;&gt;();

           <span style="color: blue;">public void </span>AddError(<span style="color: blue;">string </span>propertyName, <span style="color: blue;">string </span>error)
           {
               <span style="color: blue;">if </span>(!errors.ContainsKey(propertyName))
                   errors[propertyName] = <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: blue;">string</span>&gt;();

               <span style="color: blue;">if </span>(!errors[propertyName].Contains(error))
               {
                   errors[propertyName].Add(error);
                   RaiseErrorsChanged(propertyName);
               }
           }

           <span style="color: blue;">public void </span>RemoveError(<span style="color: blue;">string </span>propertyName, <span style="color: blue;">string </span>error)
           {
               <span style="color: blue;">if </span>(errors.ContainsKey(propertyName) &amp;&amp;
                   errors[propertyName].Contains(error))
               {
                   errors[propertyName].Remove(error);
                   <span style="color: blue;">if </span>(errors[propertyName].Count == 0)
                       errors.Remove(propertyName);
                   RaiseErrorsChanged(propertyName);
               }
           }

           <span style="color: blue;">public void </span>RaiseErrorsChanged(<span style="color: blue;">string </span>propertyName)
           {
               <span style="color: blue;">if </span>(ErrorsChanged != <span style="color: blue;">null</span>)
                   ErrorsChanged(<span style="color: blue;">this</span>,
                       <span style="color: blue;">new </span><span style="color: #2b91af;">DataErrorsChangedEventArgs</span>(propertyName));
           }

       }</pre>
<p>Comme vous pouvez le remarquer, nous avons ajouté une collection de type dictionnaire&lt;string,List&lt;string&gt;&gt; pour indiquer que pour une propriété nous pouvons avoir plusieurs messages, ainsi que deux méthodes AddError et RemoveError qui agissent sur cette collection et lèvent l’évènement indiquant qu’une modification a été apportée sur la propriété courante.</p>
<p>Du côté de l’interface INotifyDataErrorInfo, la propriété HasErrors regarde si le dictionnaire contient des erreurs et GetErrors s’appuie également sur le dictionnaire pour retourner tous les messages d’une propriété.</p>
<p>Enfin dernier point à modifier pour que cela puisse fonctionner. Remplacez dans le code XAML la propriété ValidatesOnDataErrors par  ValidatesOnNotifyDataErrors.</p>
<pre class="code">    <span style="color: blue;">&lt;</span><span style="color: #a31515;">TextBox </span><span style="color: red;">Width</span><span style="color: blue;">="200" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Nom</span><span style="color: blue;">,</span><span style="color: red;">Mode</span><span style="color: blue;">=TwoWay,
        </span><span style="color: red;">ValidatesOnNotifyDataErrors</span><span style="color: blue;">=True,</span><span style="color: red;">NotifyOnValidationError</span><span style="color: blue;">=True}"/&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a>Et voilà, vous devriez obtenir un écran dans ce style, suivant les infos que vous entrez:</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles98E581/image[27].png"><img style="display: inline; border: 0px;" title="image_thumb[33]" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb33.png" border="0" alt="image_thumb[33]" width="486" height="257" /></a></p>
<p>Je pense qu’à la suite de ce billet, vous avez les bases pour faire de la validation de données, donc à vos claviers.</p>
<p><a href="http://11011.net/software/vspaste"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/06/13/valider-les-donnes-avec-silverlight/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4 &#8211; Notification Window</title>
		<link>http://blog.experida.fr/2010/06/09/silverlight-4-notification-window/</link>
		<comments>http://blog.experida.fr/2010/06/09/silverlight-4-notification-window/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 19:20:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[NotificationWindow]]></category>
		<category><![CDATA[Silverlight4]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/?p=81</guid>
		<description><![CDATA[Qu’est ce qu’une notification window. Il s’agit d’un contrôle, permettant d’afficher sur l’écran de l’utilisateur, une alerte qui disparaît quelques secondes plus tard, un peu comme quand vous avez un ami qui se connecte sur msn ou autre messagerie instantanée. Le seul prérequis à son utilisation est que vous soyez en mode OOB (Out of [...]]]></description>
			<content:encoded><![CDATA[<p>Qu’est ce qu’une notification window. Il s’agit d’un contrôle, permettant d’afficher sur l’écran de l’utilisateur, une alerte qui disparaît quelques secondes plus tard, un peu comme quand vous avez un ami qui se connecte sur msn ou autre messagerie instantanée. Le seul prérequis à son utilisation est que vous soyez en mode OOB (Out of Browser). Si vous tentez d&#8217;afficher une Notification Window avec une application qui ne s&#8217;éxécute pas dans ce mode vous obtiendrez une exceptionn comme celle-ci.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb.png" border="0" alt="image" width="600" height="118" /></a></p>
<p><span id="more-81"></span></p>
<p>Pour faire en sorte que votre application soit donc utilisable en mode OOB, il vous suffit juste d’aller dans les propriétés de  l’application Silverlight et de sélectionner la checkbox “Enable running  application out of browser” comme montré sur cette image.</p>
<p><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb1.png" border="0" alt="image" width="300" height="67" /></p>
<p>Pour forcer l’utilisateur à installer l’application une fois lancée, mettons en place une interface avec un boutton chargé de l’installation, uniquement visible le temps que l’installation n’est pas faite., et un second bouton  “StartButton&#8221; visible une fois l’installation faite,chargé d’afficher une NotificationWindow. Le statut de l’installation est accessible via la propriété InstallState de l’application.</p>
<div>
<pre class="code"><span style="color: blue;">if </span>(<span style="color: #2b91af;">App</span>.Current.InstallState == <span style="color: #2b91af;">InstallState</span>.Installed)
           {
               InstallBtn.Visibility = System.Windows.<span style="color: #2b91af;">Visibility</span>.Collapsed;
               StartBtn.Visibility = System.Windows.<span style="color: #2b91af;">Visibility</span>.Visible;
           }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Etant donné que les autres boutons ne seront visibles qu’une fois l’application installée, vous devriez obtenir le visuel suivant.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image2.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb2.png" border="0" alt="image" width="216" height="232" /></a></p>
<p>Au niveau du handler associé à ce bouton, nous retrouvons le code permettant de lancer l’installation.</p>
<div>
<pre class="code"><span style="color: #2b91af;">App</span>.Current.Install();</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Cliquez sur le bouton pour démarrer la procédure. Silverlight vous demande de confirmer l’installation, en précisant les raccourcis à créer.</p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image3.png"><img style="display: inline; border-width: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb3.png" border="0" alt="image" width="282" height="127" /></a></p>
<p>Cliquez sur ok, l’application est installée. Pour l’exécuter rendez-vous dans le menu Démarrer.</p>
<p>Il nous reste plus qu’à créer une NotificationWindow. Pour le faire, ajoutez un handler associé au click  du StartButton, puis dans le corps de la méthode, instanciez une NotificationWindow, précisez, sa largeur et sa hauteur ainsi qu’un contenu. Enfin appelez la méthode Show en lui passant un temps en millisecondes, pour montrer la fenêtre.</p>
<div>
<pre class="code"><span style="color: blue;">private void </span>Button_Click(<span style="color: blue;">object </span>sender, <span style="color: #2b91af;">RoutedEventArgs </span>e)
       {

           <span style="color: #2b91af;">NotificationWindow </span>nw = <span style="color: blue;">new </span><span style="color: #2b91af;">NotificationWindow</span>();
           nw.Width = 300;
           nw.Height=60;
           nw.Content = <span style="color: blue;">new </span><span style="color: #2b91af;">TextBlock </span>{ Text = <span style="color: #a31515;">"Je fais une démo" </span>};
           nw.Show(4000);
       }</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Comme vous pouvez le voir, dans cet exemple très simple, nous passons à la propriété Content juste un élément TextBlock, histoire d’afficher un message. Comme cette propriété attend un type FrameworElement, vous pouvez  par exemple lui assigner  un custom contrôle.</p>
<p>Pour créer ce custom control, ajoutez juste un nouvel item et sélectionnez  Silverlight Templated Control dans le TemplateWizard. Vous devriez  en plus des fichiers précédents,  avoir un dossier thème contenant un generic.xaml pour définir l’aspect visuel du contrôle, plus un fichier cs à la racine du projet pour définir la logique du contrôle.</p>
<p>Ce que nous voulons faire, c’est afficher une NotificationWindows avec un titre et un contenu.</p>
<p>Dans le generic.xaml nous redéfinissons le template du contrôle avec un  border comme élément conteneur et un stackpanel contenant le champs texte du header et un autre du content.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">Style </span><span style="color: red;">TargetType</span><span style="color: blue;">="local:NotificationContent"&gt;
        &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Width" </span><span style="color: red;">Value</span><span style="color: blue;">="400"/&gt;
        &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Height" </span><span style="color: red;">Value</span><span style="color: blue;">="70"/&gt;
        &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Foreground" </span><span style="color: red;">Value</span><span style="color: blue;">="White"/&gt;
        &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Template"&gt;
            &lt;</span><span style="color: #a31515;">Setter.Value</span><span style="color: blue;">&gt;
                &lt;</span><span style="color: #a31515;">ControlTemplate </span><span style="color: red;">TargetType</span><span style="color: blue;">="local:NotificationContent"&gt;
                    &lt;</span><span style="color: #a31515;">Border
                        </span><span style="color: red;">BorderBrush</span><span style="color: blue;">="Yellow"
                        </span><span style="color: red;">BorderThickness</span><span style="color: blue;">="2"
                        </span><span style="color: red;">Background</span><span style="color: blue;">="Black"
                        </span><span style="color: red;">Height</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Height</span><span style="color: blue;">}"
                        </span><span style="color: red;">Width</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Width</span><span style="color: blue;">}"&gt;
                        &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
                            &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Name</span><span style="color: blue;">="PART_HeaderText" </span><span style="color: red;">Foreground</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Foreground</span><span style="color: blue;">}" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">HeaderText</span><span style="color: blue;">}"/&gt;
                            &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Name</span><span style="color: blue;">="PARTContentText" </span><span style="color: red;">Foreground</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Foreground</span><span style="color: blue;">}" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">ContentText</span><span style="color: blue;">}" /&gt;
                        &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
                    &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
                &lt;/</span><span style="color: #a31515;">ControlTemplate</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">Setter.Value</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">Setter</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">Style</span><span style="color: blue;">&gt;
</span></pre>
<p> </p>
<p>Vous noterez également au passage, la présence du Binding sur deux propriétés que l’on a ajouté  dans le code logique du contrôle.</p>
<pre class="code"><span style="color: blue;">public string </span>HeaderText
{
    <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>(<span style="color: blue;">string</span>)GetValue(HeaderTextProperty); }
    <span style="color: blue;">set </span>{ SetValue(HeaderTextProperty, <span style="color: blue;">value</span>); }
}

<span style="color: blue;">public static readonly </span><span style="color: #2b91af;">DependencyProperty </span>HeaderTextProperty =
    <span style="color: #2b91af;">DependencyProperty</span>.Register(<span style="color: #a31515;">"HeaderText"</span>, <span style="color: blue;">typeof</span>(<span style="color: blue;">string</span>), <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">NotificationContent</span>), <span style="color: blue;">null</span>);

<span style="color: blue;">public string </span>ContentText
{
    <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>(<span style="color: blue;">string</span>)GetValue(ContentTextProperty); }
    <span style="color: blue;">set </span>{ SetValue(ContentTextProperty, <span style="color: blue;">value</span>); }
}

<span style="color: blue;">public static readonly </span><span style="color: #2b91af;">DependencyProperty </span>ContentTextProperty =
    <span style="color: #2b91af;">DependencyProperty</span>.Register(<span style="color: #a31515;">"ContentText"</span>, <span style="color: blue;">typeof</span>(<span style="color: blue;">string</span>), <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">NotificationContent</span>), <span style="color: blue;">null</span>);</pre>
<p> </p>
<p>Pour utiliser ce contrôle, il ne vous reste plus qu’à l’instancier et à l’assigner à la propriété content de la NotificationWindow.</p>
<pre class="code"><span style="color: #2b91af;">NotificationWindow </span>nw = <span style="color: blue;">new </span><span style="color: #2b91af;">NotificationWindow</span>();
         nw.Width = 300;
         nw.Height = 60;

         content.HeaderText = <span style="color: #a31515;">"Mon Titre"</span>;
         content.ContentText = <span style="color: #a31515;">"Corps de la notification"</span>;
         content.Width = nw.Width;
         content.Height = nw.Height;
         nw.Content = content;</pre>
<p> </p>
<p><a href="http://blog.experida.fr/wp-content/uploads/2010/06/image4.png"><img style="display: inline; border: 0px;" title="image" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb5.png" border="0" alt="image" width="370" height="213" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/06/09/silverlight-4-notification-window/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Utilisation du ItemTemplateSelector</title>
		<link>http://blog.experida.fr/2010/06/04/utilisation-du-itemtemplateselector/</link>
		<comments>http://blog.experida.fr/2010/06/04/utilisation-du-itemtemplateselector/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 22:00:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[DataTemplate]]></category>
		<category><![CDATA[ItemTemplateSelector]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/06/03/utilisation-du-itemtemplateselector/</guid>
		<description><![CDATA[En Wpf comme en Silverlight, plusieurs cas peuvent se présenter à nous dans le choix d&#8217;un template, lorsqu&#8217;on décide d&#8217;afficher une liste de données. 1- Soit notre liste contient des données homogènes, c&#8217;est à dire même type ou alors sans aucun critère de distinction, et on affiche un Template unique pour tous les Items via [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">En Wpf comme en Silverlight, plusieurs cas peuvent se présenter à nous dans le choix d&#8217;un template, lorsqu&#8217;on décide d&#8217;afficher une liste de données.</p>
<p style="text-align: justify;">1- Soit notre liste contient des données homogènes, c&#8217;est à dire même type ou alors sans aucun critère de distinction, et on affiche un Template unique pour tous les Items via la propriété ItemTemplate</p>
<p style="text-align: justify;">2- Soit notre liste contient différents types, ou des valeurs internes différentes nécessitant la mise en place d&#8217;un Selector pour écrire la logique permettant de faire le choix du bon Template à afficher dans notre application.</p>
<p style="text-align: justify;"><span id="more-10"></span></p>
<p style="text-align: justify;">Nous traiterons ici la cas du ItemTemplateSelector, applicable pour les contrôles héritant de ItemsControl, mais sachez qu&#8217;il existe également un ContentTemplateSelector pour les Content contrôles, le ItemContainerStyleSelector&#8230; Attention, si vous saisissez un ItemTemplate, le Selector sera tout simplement ignoré</p>
<p style="text-align: justify;"><span style="text-decoration: underline;"><strong>Exemple cas 1:</strong></span></p>
<p style="text-align: justify;">Imaginons un classe Salarie qui implémente l&#8217;interface IPersonnel. Cette interface spécifie simplement deux propriétés, à savoir Nom et Prenom.<span style="font-size: x-small;"> </span></p>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IPersonnel
  </span>{

      <span style="color: blue;">string </span>Nom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
      <span style="color: blue;">string </span>Prenom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

  }

  <span style="color: blue;">public class </span><span style="color: #2b91af;">Salarie </span>: <span style="color: #2b91af;">IPersonnel
  </span>{
      <span style="color: blue;">public string </span>Nom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
      <span style="color: blue;">public string </span>Prenom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

  }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Dans le code behind ou ViewModel si vous appliquez le pattern MVVM, ajoutez une collection de Salariés, puis dans le code xaml de votre vue, ajoutez une ListBox ou tout autre ItemControl, et faites le Binding sur la propriété ItemsSource et indiquez un ItemTemplate pour le visuel de chaque item de de la ListBox;</p>
<p><span style="text-decoration: underline;">Ajout des données au DataContext (Code Behind)</span></p>
<pre class="code"><span style="color: blue;">this</span>.DataContext = <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">IPersonnel</span>&gt; {
    <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{ Nom=<span style="color: #a31515;">"Arnaudet"</span>,Prenom=<span style="color: #a31515;">"Alexandre"</span>},
    <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"CLT"</span>,Prenom=<span style="color: #a31515;">"Services"</span>}
};</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;">Code XAML</span></p>
<pre class="code">        <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}"&gt;
            &lt;</span><span style="color: #a31515;">ListBox.ItemTemplate</span><span style="color: blue;">&gt;
                &lt;</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
                    &lt;</span><span style="color: #a31515;">Border </span><span style="color: red;">CornerRadius</span><span style="color: blue;">="5"
                        </span><span style="color: red;">BorderBrush</span><span style="color: blue;">="Black"
                        </span><span style="color: red;">BorderThickness</span><span style="color: blue;">="1"
                        </span><span style="color: red;">Padding</span><span style="color: blue;">="10"&gt;
                        &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
                            &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="Salarie" </span><span style="color: red;">FontWeight</span><span style="color: blue;">="Bold"/&gt;
                            &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Nom</span><span style="color: blue;">}" /&gt;
                        &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
                    &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
                &lt;/</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">ListBox.ItemTemplate</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">ListBox</span><span style="color: blue;">&gt;
</span></pre>
<p><span style="text-decoration: underline;">Résultat</span></p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfilesB955A1/image3.png"><img style="display: inline; border-width: 0px;" title="image_thumb4" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb4.png" border="0" alt="image_thumb4" width="244" height="160" /></a> <a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;"><strong>Exemple cas 2:</strong></span></p>
<p>Dans cet exemple, nous allons garder la classe salarie, mais ajouter une seconde classe Directeur. Comme salarie elle implémente IPersonnel de manière à ce que Directeur fournisse les données minimum pour être un membre du personnel, mais ajoute la possibilité d’avoir des salariés sous ses ordres.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Directeur </span>: <span style="color: #2b91af;">IPersonnel
</span>{
    <span style="color: blue;">#region </span>IPersonnel Members

    <span style="color: blue;">public string </span>Nom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
    <span style="color: blue;">public string </span>Prenom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

    <span style="color: blue;">public </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">IPersonnel</span>&gt; Salaries { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

    <span style="color: blue;">#endregion
</span>}</pre>
<p>Comme précédemment, nous allons ajouter dans le code behind, une liste de IPersonnel au DataContext, mais cette fois avec des salaries et des directeurs.</p>
<pre class="code"><span style="color: blue;">this</span>.DataContext = <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">IPersonnel</span>&gt; {
               <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{ Nom=<span style="color: #a31515;">"Arnaudet"</span>,Prenom=<span style="color: #a31515;">"Alexandre"</span>},
               <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"Greg"</span>,Prenom=<span style="color: #a31515;">"Greg"</span>},
               <span style="color: blue;">new </span><span style="color: #2b91af;">Directeur</span>{Nom=<span style="color: #a31515;">"Damien"</span>,Prenom=<span style="color: #a31515;">"Damien"</span>,
                Salaries= <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">IPersonnel</span>&gt;{
                   <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"PL"</span>,Prenom=<span style="color: #a31515;">"PL"</span>},
                   <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"Jérôme"</span>,Prenom=<span style="color: #a31515;">"Jérôme"</span>},
                   <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{ Nom=<span style="color: #a31515;">"Arnaudet"</span>,Prenom=<span style="color: #a31515;">"Alexandre"</span>},
                   <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"Greg"</span>,Prenom=<span style="color: #a31515;">"Greg"</span>},
                }},
               <span style="color: blue;">new </span><span style="color: #2b91af;">Directeur</span>{Nom=<span style="color: #a31515;">"Ludo"</span>,Prenom=<span style="color: #a31515;">"Ludo"</span>,
                Salaries= <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">IPersonnel</span>&gt;{
                   <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"Manu"</span>,Prenom=<span style="color: #a31515;">"Manu"</span>},
                   <span style="color: blue;">new </span><span style="color: #2b91af;">Salarie</span>{Nom=<span style="color: #a31515;">"Celine"</span>,Prenom=<span style="color: #a31515;">"Celine"</span>}
                }}
           };</pre>
<p>Si on ne va pas plus loin, on retrouve simplement à l’écran une liste de 4 salariés</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfilesB955A1/image7.png"><img style="display: inline; border-width: 0px;" title="image_thumb10" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb10.png" border="0" alt="image_thumb10" width="206" height="244" /></a></p>
<p>Ce que nous voulons c’est créer un visuel différent lorsqu’on à faire à un simple salarié, ou bien à un directeur et ses salariés, c’est là qu’entre en jeu la propriété ItemTemplateSelector. Dès lors que vous aurez spécifié un DataTemplateSelector en tant que ressource sur cette propriété, la méthode SelectTemplate va être recherchée.</p>
<p>Le Selector doit hériter de la classe DataTemplateSelector, puis surcharger la méthode SelectTemplate qui retourne un DataTemplate, celui sélectionné suite à la logique appliquée. Alors ici, nous allons faire simple en ne regardant que le type de IPersonnel</p>
<p>Si c’est un Directeur on retourne le DataTemplate <strong>DirecteurDataTemplate</strong>, sinon <strong>SalarieDataTemplate</strong>.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">PersonnelSelector </span>: <span style="color: #2b91af;">DataTemplateSelector </span>{
        <span style="color: blue;">public override </span><span style="color: #2b91af;">DataTemplate
            </span>SelectTemplate(<span style="color: blue;">object </span>item, <span style="color: #2b91af;">DependencyObject </span>container)
        {
            <span style="color: blue;">if </span>(item != <span style="color: blue;">null </span>&amp;&amp; item <span style="color: blue;">is </span><span style="color: #2b91af;">Directeur</span>)
                <span style="color: blue;">return </span><span style="color: #2b91af;">Application</span>.Current
                    .TryFindResource(<span style="color: #a31515;">"DirecteurDataTemplate"</span>) <span style="color: blue;">as </span><span style="color: #2b91af;">DataTemplate</span>;

            <span style="color: blue;">return </span><span style="color: #2b91af;">Application</span>.Current
                .TryFindResource(<span style="color: #a31515;">"SalarieDataTemplate"</span>) <span style="color: blue;">as </span><span style="color: #2b91af;">DataTemplate</span>;
        }
    }</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Les deux DataTemplate indiqués ci-dessus sont créés dans les ressources de l’application</p>
<pre class="code">   <span style="color: blue;">&lt;</span><span style="color: #a31515;">Application.Resources</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">DataTemplate </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="SalarieDataTemplate"&gt;
            &lt;</span><span style="color: #a31515;">Border </span><span style="color: red;">CornerRadius</span><span style="color: blue;">="5"
                        </span><span style="color: red;">BorderBrush</span><span style="color: blue;">="Black"
                        </span><span style="color: red;">BorderThickness</span><span style="color: blue;">="1"
                        </span><span style="color: red;">Padding</span><span style="color: blue;">="10"&gt;
                &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
                    &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="Salarie" </span><span style="color: red;">FontWeight</span><span style="color: blue;">="Bold"/&gt;
                    &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Nom</span><span style="color: blue;">}" /&gt;
                &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">DataTemplate </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="DirecteurDataTemplate"&gt;
            &lt;</span><span style="color: #a31515;">Border </span><span style="color: red;">CornerRadius</span><span style="color: blue;">="5"
                        </span><span style="color: red;">BorderBrush</span><span style="color: blue;">="Black"
                        </span><span style="color: red;">BorderThickness</span><span style="color: blue;">="1"
                        </span><span style="color: red;">Padding</span><span style="color: blue;">="10"&gt;
                &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Vertical"&gt;
                    &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="Salarie" </span><span style="color: red;">FontWeight</span><span style="color: blue;">="Bold"/&gt;
                    &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Nom</span><span style="color: blue;">}" /&gt;
                    &lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">Margin</span><span style="color: blue;">="20,0,0,0"
                             </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Salaries</span><span style="color: blue;">}"
                             </span><span style="color: red;">ItemTemplate</span><span style="color: blue;">=
                             "{</span><span style="color: #a31515;">StaticResource </span><span style="color: red;">SalarieDataTemplate</span><span style="color: blue;">}"/&gt;
                &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">Application.Resources</span><span style="color: blue;">&gt;
</span></pre>
<p>Il nous reste plus qu’à modifier notre code xaml pour référencer le Selector et supprimer l’ItemTemplate actuel.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">Grid.Resources</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">local</span><span style="color: blue;">:</span><span style="color: #a31515;">PersonnelSelector </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="Selector"/&gt;
        &lt;/</span><span style="color: #a31515;">Grid.Resources</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}"
                 </span><span style="color: red;">ItemTemplateSelector</span><span style="color: blue;">="{</span><span style="color: #a31515;">StaticResource </span><span style="color: red;">Selector</span><span style="color: blue;">}"&gt;
        &lt;/</span><span style="color: #a31515;">ListBox</span><span style="color: blue;">&gt;
</span></pre>
<p>Ce qui nous donne comme résultat</p>
<table border="0" cellspacing="0" cellpadding="2" width="534">
<tbody>
<tr>
<td width="10" valign="top"><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfilesB955A1/image5.png"><img style="display: inline; border-width: 0px;" title="image_thumb6" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb6.png" border="0" alt="image_thumb6" width="183" height="585" /></a></td>
<td width="530" valign="top">Comme vous pouvez le voir dans le cas du Directeur, nous retrouvons bien ses salariés.Dans le cadre de notre exemple, vous pourriez très bien ajouter une nouvelle entité implémentant IPersonnel et crééer comme on vient de le faire son propre visuel (DataTemplate) en utilisant le Selector</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/06/04/utilisation-du-itemtemplateselector/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Window object, UI Thread et COM</title>
		<link>http://blog.experida.fr/2010/06/01/window-object-ui-thread-et-com/</link>
		<comments>http://blog.experida.fr/2010/06/01/window-object-ui-thread-et-com/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 22:30:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[COM object]]></category>
		<category><![CDATA[Dispatcher]]></category>
		<category><![CDATA[UIThread]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/31/window-object-ui-thread-et-com/</guid>
		<description><![CDATA[Généralement lorsqu’on développe une application, les opérations prenant du temps sont réalisées dans des thread à part pour ne pas bloquer l’interface de l’application. On peut prendre par exemple le cas du BackgroundWorker qui permet d’y parvenir facilement avec le code suivant BackgroundWorker worker = new BackgroundWorker(); //Handler appelé lors de l'exécution du thread worker.DoWork [...]]]></description>
			<content:encoded><![CDATA[<p>Généralement lorsqu’on développe une application, les opérations prenant du temps sont réalisées dans des thread à part pour ne pas bloquer l’interface de l’application. On peut prendre par exemple le cas du BackgroundWorker qui permet d’y parvenir facilement avec le code suivant</p>
<p><span id="more-19"></span></p>
<pre class="code"><span style="color: #2b91af;">BackgroundWorker </span>worker = <span style="color: blue;">new </span><span style="color: #2b91af;">BackgroundWorker</span>();

<span style="color: green;">//Handler appelé lors de l'exécution du thread
</span>worker.DoWork += (s, ev) =&gt; { };

<span style="color: green;">//Handler appelé une que l'opération dans le thread est terminée
</span>worker.RunWorkerCompleted += (s, ev) =&gt; { };

worker.RunWorkerAsync();</pre>
<p>Récemment je me suis retrouvé avec une application manipulant des objets COM. Afin de pouvoir faire du Binding sur ces objets et profiter de la notification avec l’interface INotifyPropertyChanged, j’ai créé un objet wrapper prenant en paramètre un interop qui se charge simplement de s’abonner à un event créé dans les objets COM et de propager la notification en déclenchant un event PropertyChanged.</p>
<p>Le seul problème c’est que ces objets COM sont enregistrés dans le registre avec un ThreadModel = “Apartment” ce qui signifie qu’ils ne peuvent être utilisés que sur un thread avec un ApartmentState STA (Single Threaded Apartment).</p>
<p>Un objet COM créé par un STAThread ne peut être manipulé que par ce même thread. Or comme indiqué plus haut la vue va se binder dessus et en éditant par exemple une textbox liée à une propriété, la propriété doit être mise à jour. Le thread mettant à jour la donnée est l’UI thread qui fonctionne en STA. Cela implique qu’on ne peut modifier ces objets sur un autre thread que celui de l’interface.</p>
<p><span style="text-decoration: underline;">Inconvénient:</span></p>
<p>J’ai créé un contrôle Loader qui s’affiche normalement lorsqu’une opération longue est en cours  d’exécution dans un autre thread. Avec ce que l’on vient de dire quelques lignes ci-dessus, mon contrôle loader se retrouve figé.</p>
<p>Pour contourner ce problème et ayant dans mon viewModel une propriété indiquant si une opération est en cours, j&#8217;ai créé une classe avec une propriété attachée qui récupère le statut de l&#8217;opération et qui selon son état true / false, instancie le contrôle Loader qui hérite de Window dans un nouveau thread.</p>
<p>Lorsqu&#8217;on lance une application WPF, l&#8217;application démarre pour nous un dispatcher pour le thread UI. Ici on le fait  à la mano grâce à la méthode statique Dispatcher.Run. Ainsi la fenêtre principale et la fenêtre loader tournent chacune sur leur propre UI thread.</p>
<p>Je vous laisse regarder le code ci-dessous qui se charge de ça. Notez au passage l&#8217;appel de la méthode Dispatcher.InvokeShutdown une fois la fenêtre fermée pour terminer le dispatcher.</p>
<p>Avec quelques styles il est également facile de transformer le visage du loader et faire en sorte de le montrer comme étant totalement intégré à la fenêtre principale.</p>
<pre class="code"><span style="color: #2b91af;">Panel </span>rootLayout = d <span style="color: blue;">as </span><span style="color: #2b91af;">Panel</span>;

          <span style="color: blue;">if </span>(rootLayout == <span style="color: blue;">null</span>)
              <span style="color: blue;">return</span>;

          <span style="color: blue;">bool </span>active = e.NewValue != <span style="color: blue;">null </span>? (<span style="color: blue;">bool</span>)e.NewValue : <span style="color: blue;">false</span>;

          <span style="color: blue;">if </span>(active)
          {
              <span style="color: #2b91af;">Thread </span>thread = <span style="color: blue;">new </span><span style="color: #2b91af;">Thread</span>((data) =&gt;
              {
                  NotificationData nData = (NotificationData)data;
                  indicator = <span style="color: blue;">new
                      </span>BusyIndicator(nData.ParentWidth, nData.ParentHeight);
                  indicator.Message = nData.Message;
                  indicator.Show();

                  indicator.Closed += (s, ev) =&gt;
                  indicator.Dispatcher.InvokeShutdown();

                  System.Windows.Threading.<span style="color: #2b91af;">Dispatcher</span>.Run();
              });
              thread.SetApartmentState(<span style="color: #2b91af;">ApartmentState</span>.STA);
              thread.IsBackground = <span style="color: blue;">true</span>;
              thread.Start(<span style="color: blue;">new </span>NotificationData
              {
                  Message = d.GetValue(MessageProperty).ToString(),
                  ParentHeight = rootLayout.ActualHeight,
                  ParentWidth = rootLayout.ActualWidth
              });
          }
          <span style="color: blue;">else
          </span>{
              <span style="color: blue;">if </span>(indicator != <span style="color: blue;">null</span>)
              {
                  indicator.Dispatcher.Invoke(<span style="color: blue;">new </span><span style="color: #2b91af;">Action</span>(() =&gt;
                  {
                      indicator.Close();
                  }));
              }
          }</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/06/01/window-object-ui-thread-et-com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Grouper et trier simplement les donn&#233;es gr&#226;ce au CollectionViewSource</title>
		<link>http://blog.experida.fr/2010/05/29/grouper-et-trier-simplement-les-donnes-grce-au-collectionviewsource/</link>
		<comments>http://blog.experida.fr/2010/05/29/grouper-et-trier-simplement-les-donnes-grce-au-collectionviewsource/#comments</comments>
		<pubDate>Sat, 29 May 2010 19:29:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[CollectionViewSource]]></category>
		<category><![CDATA[Groupe]]></category>
		<category><![CDATA[Tri]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/29/grouper-et-trier-simplement-les-donnes-grce-au-collectionviewsource/</guid>
		<description><![CDATA[Il arrive régulièrement que l’on veuille afficher des données groupées ou triées sur une propriété du type d’objet présent dans la collection. Avec le CollectionViewSource il est plutôt simple d’y parvenir, en ne faisant que du XAML. Si vous désirez utiliser la fonctionnalité du filtre vous devrez passer par le code behind. Les fonctionnalités de [...]]]></description>
			<content:encoded><![CDATA[<p>Il arrive régulièrement que l’on veuille afficher des données groupées ou triées sur une propriété du type d’objet présent dans la collection.</p>
<p>Avec le CollectionViewSource il est plutôt simple d’y parvenir, en ne faisant que du XAML. Si vous désirez utiliser la fonctionnalité du filtre vous devrez passer par le code behind.</p>
<p>Les fonctionnalités de tri, filtre et groupe ne sont pas nouvelles en WPF, comme en Silverlight, mais auparavant vous deviez obligatoirement passer par le code behind pour les implémenter ce qui ne facilitait pas leur utilisation avec des outils comme blend.</p>
<p><span id="more-26"></span></p>
<p>Dès que vous passez une collection de données à la propriété Source du CollectionViewSource, ce dernier va générer une vue accessible via sa propriété View.  C’est sur cette vue jouant le rôle de wrapper que l’on peut ajouter le tri par exemple.</p>
<p>Prenons un cas simple.</p>
<p>Imaginons une classe collaborateur avec les propriétés suivantes.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">Collaborateur
</span>{
    <span style="color: blue;">public string </span>Nom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
    <span style="color: blue;">public string </span>Prenom { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
    <span style="color: blue;">public int </span>Age { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
}</pre>
<p>Une fois notre liste de collaborateurs créée nous l’assignons au DataContext de la fenêtre principale de l’application.</p>
<pre class="code"><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Collaborateur</span>&gt; collaborateurs = <span style="color: blue;">new </span><span style="color: #2b91af;">List</span>&lt;<span style="color: #2b91af;">Collaborateur</span>&gt; {
               <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur
               </span>{
                   Nom = <span style="color: #a31515;">"Arnaudet"</span>,
                   Prenom = <span style="color: #a31515;">"Alexandre"</span>,
                   Age = 25
               },
               <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur</span>{
                   Nom=<span style="color: #a31515;">"Arnaudet"</span>,
                   Prenom=<span style="color: #a31515;">"Julien"</span>,
                   Age=19
               },
               <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur</span>{
                   Nom = <span style="color: #a31515;">"toto"</span>,
                   Prenom=<span style="color: #a31515;">"Bernard"</span>,
                   Age=54
               },
               <span style="color: blue;">new </span><span style="color: #2b91af;">Collaborateur</span>{
                   Nom=<span style="color: #a31515;">"titi"</span>,
                   Prenom=<span style="color: #a31515;">"Stephane"</span>,
                   Age=25
               },
           };

           <span style="color: blue;">this</span>.DataContext = collaborateurs;</pre>
<p>Ensuite dans le code XAML ajoutez une ListBox et avec la propriété ItemsSource, faites le binding sur le DataContext.</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}"/&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Afin de rendre l’interface un peu plus jolie, personnalisons le ItemTemplate.</p>
<pre class="code">      <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}"&gt;
         &lt;</span><span style="color: #a31515;">ListBox.ItemTemplate</span><span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
           &lt;</span><span style="color: #a31515;">Border </span><span style="color: red;">CornerRadius</span><span style="color: blue;">="5" </span><span style="color: red;">Padding</span><span style="color: blue;">="5" </span><span style="color: red;">BorderBrush</span><span style="color: blue;">="Black"
                   </span><span style="color: red;">BorderThickness</span><span style="color: blue;">="1"&gt;
             &lt;</span><span style="color: #a31515;">StackPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Horizontal"&gt;
              &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Margin</span><span style="color: blue;">="15,0,0,0" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Nom</span><span style="color: blue;">}"/&gt;
              &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Margin</span><span style="color: blue;">="15,0,0,0" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Prenom</span><span style="color: blue;">}"/&gt;
              &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Margin</span><span style="color: blue;">="15,0,0,0" </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Age</span><span style="color: blue;">}"/&gt;
             &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
           &lt;/</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
         &lt;/</span><span style="color: #a31515;">ListBox.ItemTemplate</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">ListBox</span><span style="color: blue;">&gt;
</span></pre>
<p>Vous devriez maintenant voir quelque chose ressemblant à ceci:</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles314E4A3/image25.png"><img style="display: inline; border: 0px;" title="image_thumb30" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb30.png" border="0" alt="image_thumb30" width="244" height="149" /></a></p>
<p>Quand l’utilisateur voit cette interface, il dit: “oui mais je souhaiterais que ces données soit triées par âge”. Ok c’est là qu’entre en jeu le CollectionViewSource. Retournons dans le code xaml et ajoutons le dans les ressources  de notre élément root.</p>
<div>
<pre class="code">        <span style="color: blue;">&lt;</span><span style="color: #a31515;">Grid.Resources</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">CollectionViewSource </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Key</span><span style="color: blue;">="CollaborateursViewByAge"
                </span><span style="color: red;">Source</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}"&gt;
                &lt;</span><span style="color: #a31515;">CollectionViewSource.SortDescriptions</span><span style="color: blue;">&gt;
                    &lt;</span><span style="color: #a31515;">scm</span><span style="color: blue;">:</span><span style="color: #a31515;">SortDescription
                        </span><span style="color: red;">PropertyName</span><span style="color: blue;">="Age"
                        </span><span style="color: red;">Direction</span><span style="color: blue;">="Ascending"/&gt;
                &lt;/</span><span style="color: #a31515;">CollectionViewSource.SortDescriptions</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">CollectionViewSource</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">Grid.Resources</span><span style="color: blue;">&gt;
</span></pre>
</div>
<p>Premièrement notez que la propriété Source pointe sur l’élément courant ajouté au dataContext de notre vue et que nous avons un élément SortDescription sur lequel on indique la propriété à trier et la direction Ascending ou Descending.</p>
<p>Deuxièmement, il faut modifier également la propriété ItemsSource de la ListeBox pour qu’elle fasse le Binding sur le CollectionViewSource et non plus sur le DataContext.</p>
<pre class="code">  <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">Source</span><span style="color: blue;">={</span><span style="color: #a31515;">StaticResource </span><span style="color: red;">CollaborateursViewByAge</span><span style="color: blue;">}}"&gt;</span></pre>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles314E4A3/image24.png"><img style="display: inline; border: 0px;" title="image_thumb29" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb29.png" border="0" alt="image_thumb29" width="244" height="176" /></a></p>
<p>Maintenant, imaginez que vous vouliez grouper les données par Nom. De la même manière qu’on a ajouté un élément SortDescription, on va ajouter au CollectionViewSource un PropertyGroupDescription.</p>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">CollectionViewSource.GroupDescriptions</span><span style="color: blue;">&gt;
                    &lt;</span><span style="color: #a31515;">PropertyGroupDescription </span><span style="color: red;">PropertyName</span><span style="color: blue;">="Nom"/&gt;
                &lt;/</span><span style="color: #a31515;">CollectionViewSource.GroupDescriptions</span><span style="color: blue;">&gt;
</span></pre>
<p>Ce qui nous donne comme résultat:</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles314E4A3/image23.png"><img style="display: inline; border: 0px;" title="image_thumb28" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb28.png" border="0" alt="image_thumb28" width="244" height="173" /></a></p>
<p>Enfin pour mettre en valeur les différents groupes, nous allons afficher en tête de chaque groupe le nom sur lequel on se base pour grouper, grâce à la modification de la propriété GroupStyle de la ListBox.</p>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox.GroupStyle</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">GroupStyle</span><span style="color: blue;">&gt;
             &lt;</span><span style="color: #a31515;">GroupStyle.ContainerStyle</span><span style="color: blue;">&gt;
              &lt;</span><span style="color: #a31515;">Style </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">GroupItem</span><span style="color: blue;">}"&gt;
               &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Template"&gt;
                &lt;</span><span style="color: #a31515;">Setter.Value</span><span style="color: blue;">&gt;
                 &lt;</span><span style="color: #a31515;">ControlTemplate </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">GroupItem</span><span style="color: blue;">}"&gt;</span><span style="color: blue;">
                   &lt;</span><span style="color: #a31515;">GroupBox </span><span style="color: red;">Header</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}"
                             </span><span style="color: red;">BorderBrush</span><span style="color: blue;">="Transparent"
                             </span><span style="color: red;">BorderThickness</span><span style="color: blue;">="0"&gt;
                    &lt;</span><span style="color: #a31515;">ItemsPresenter</span><span style="color: blue;">/&gt;
                    &lt;/</span><span style="color: #a31515;">GroupBox</span><span style="color: blue;">&gt;</span><span style="color: blue;">
                  &lt;/</span><span style="color: #a31515;">ControlTemplate</span><span style="color: blue;">&gt;
                 &lt;/</span><span style="color: #a31515;">Setter.Value</span><span style="color: blue;">&gt;
                &lt;/</span><span style="color: #a31515;">Setter</span><span style="color: blue;">&gt;
               &lt;/</span><span style="color: #a31515;">Style</span><span style="color: blue;">&gt;
              &lt;/</span><span style="color: #a31515;">GroupStyle.ContainerStyle</span><span style="color: blue;">&gt;
             &lt;/</span><span style="color: #a31515;">GroupStyle</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">ListBox.GroupStyle</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles314E4A3/image30.png"><img style="display: inline; border: 0px;" title="image_thumb36" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb36.png" border="0" alt="image_thumb36" width="244" height="172" /></a> <a href="http://11011.net/software/vspaste"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/29/grouper-et-trier-simplement-les-donnes-grce-au-collectionviewsource/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WPF: D&#233;placer une fen&#234;tre quand sa propri&#233;t&#233; WindowStyle = &#8220;None&#8221;</title>
		<link>http://blog.experida.fr/2010/05/24/wpf-dplacer-une-fentre-quand-sa-proprit-windowstyle-none/</link>
		<comments>http://blog.experida.fr/2010/05/24/wpf-dplacer-une-fentre-quand-sa-proprit-windowstyle-none/#comments</comments>
		<pubDate>Mon, 24 May 2010 19:32:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[Move]]></category>
		<category><![CDATA[Window]]></category>
		<category><![CDATA[WindowStyle]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/24/wpf-dplacer-une-fentre-quand-sa-proprit-windowstyle-none/</guid>
		<description><![CDATA[Ce matin je décide de modifier un peu le style de mon application WPF, qui au départ, a  une toolBar ressemblant à ceci.   Souhaitant ne pas la montrer, pour donner un style différent à la fenêtre, je me suis retrouvé avec une  fenêtre qui dans la forme ressemble à l’exemple suivant. Le problème est [...]]]></description>
			<content:encoded><![CDATA[<p>Ce matin je décide de modifier un peu le style de mon application WPF, qui au départ, a  une toolBar ressemblant à ceci.</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles317CF9D/image6.png"><img style="display: inline; border: 0px;" title="image_thumb8" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb8.png" border="0" alt="image_thumb8" width="553" height="36" /></a></p>
<p> <span id="more-31"></span></p>
<p>Souhaitant ne pas la montrer, pour donner un style différent à la fenêtre, je me suis retrouvé avec une  fenêtre qui dans la forme ressemble à l’exemple suivant.</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles317CF9D/image11.png"><img style="display: inline; border: 0px;" title="image_thumb14" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb14.png" border="0" alt="image_thumb14" width="407" height="251" /></a></p>
<p>Le problème est le suivant. Ok j’ai une jolie fenêtre. Mais comment puis-je la déplacer si la toolbar ne s’affiche pas.</p>
<p>Rien de bien compliqué, il vous suffit juste de rajouter la ligne de code suivante dans le constructeur pour y arriver et le tour est joué.</p>
<pre class="code"><span style="color: blue;">this</span>.MouseDown += (s, e) =&gt; {
               DragMove();
           };</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/24/wpf-dplacer-une-fentre-quand-sa-proprit-windowstyle-none/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simuler une modal popup avec MVVM et WPF</title>
		<link>http://blog.experida.fr/2010/05/22/simuler-une-modal-popup-avec-mvvm-et-wpf/</link>
		<comments>http://blog.experida.fr/2010/05/22/simuler-une-modal-popup-avec-mvvm-et-wpf/#comments</comments>
		<pubDate>Sat, 22 May 2010 19:35:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[Modal]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Popup]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/22/simuler-une-modal-popup-avec-mvvm-et-wpf/</guid>
		<description><![CDATA[Dans ce billet je vous propose une solution pour créer une modal popup en WPF. Lorsque j&#8217;utilise le pattern MVVM,  j&#8217;ai l&#8217;habitude de définir ma View et mon ViewModel de la manière suivante.   public partial class MainWindow : Window,IMainView { public MainWindow() { InitializeComponent(); } public IMainViewModel ViewModel { get { return (IMainViewModel)this.DataContext; } [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Dans ce billet je vous propose une solution pour créer une modal popup en WPF.</p>
<p style="text-align: justify;">Lorsque j&#8217;utilise le pattern MVVM,  j&#8217;ai l&#8217;habitude de définir ma View et mon ViewModel de la manière suivante.</p>
<p style="text-align: justify;"> <span id="more-35"></span></p>
<pre class="code"><span style="color: blue;">public partial class </span><span style="color: #2b91af;">MainWindow </span>: <span style="color: #2b91af;">Window</span>,<span style="color: #2b91af;">IMainView
   </span>{
       <span style="color: blue;">public </span>MainWindow()
       {
           InitializeComponent();
       }

       <span style="color: blue;">public </span><span style="color: #2b91af;">IMainViewModel </span>ViewModel
       {
           <span style="color: blue;">get
           </span>{
               <span style="color: blue;">return </span>(<span style="color: #2b91af;">IMainViewModel</span>)<span style="color: blue;">this</span>.DataContext;
           }
           <span style="color: blue;">set
           </span>{
               <span style="color: blue;">this</span>.DataContext = <span style="color: blue;">value</span>;
           }
       }

       <span style="color: blue;">public void </span>ShowWindow()
       {
           <span style="color: blue;">this</span>.Show();
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">MainViewModel</span>:<span style="color: #2b91af;">IMainViewModel
   </span>{
       <span style="color: blue;">public </span>MainViewModel(<span style="color: #2b91af;">IMainView </span>view)
       {
           <span style="color: blue;">if </span>(view == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"view"</span>);

           <span style="color: blue;">this</span>.View = view;
           <span style="color: blue;">this</span>.View.ViewModel = <span style="color: blue;">this</span>;
       }
       <span style="color: blue;">public </span><span style="color: #2b91af;">IMainView </span>View
       {
           <span style="color: blue;">get</span>;
           <span style="color: blue;">private set</span>;
       }
   }</pre>
<p>Comme vous le remarquez, la view implémente une interface qui référence le viewmodel et le viewModel référence également la view. Deuxième point, la view est injectée via Unity ou un autre container dans le viewModel. On est dans ce qu&#8217;on appelle un modèle ViewModel First.</p>
<p style="text-align: justify;">Cette petite introduction car le code précédent va être notre point de départ.</p>
<p style="text-align: justify;">Afin de simuler la popup modal, nous avons besoin de trois éléments.</p>
<ul>
<li>
<div style="text-align: justify;">Une interface IModalView, qui permet d’indiquer que la vue doit être affichée comme une vue modale.</div>
</li>
<li>
<div style="text-align: justify;">Un custom contrôle qui sera charger d’héberger / afficher la vue avec pourquoi pas une animation. Ce custom contrôle est un content contrôle.</div>
</li>
<li>
<div style="text-align: justify;">Et enfin une classe avec une propriété attachée qui a pour but de créer une instance du customControl, d’assigner à sa propriété content, une IModalView.</div>
</li>
</ul>
<p style="text-align: justify;"><strong><span style="text-decoration: underline;">Interface IModalView</span></strong></p>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IModalView
   </span>{
       <span style="color: blue;">string </span>Title { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
       <span style="color: blue;">event </span><span style="color: #2b91af;">Action </span>closeEvent;
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p style="text-align: justify;">Chaque vue que l&#8217;on souhtaite voir apparaître comme une popup modale devra implémenter cette interface. Attention comme la vue sera injectée dans l&#8217;arbre xaml pendant l&#8217;exécution, la vue doit correspondre à un type UserControl et non Window.</p>
<p><strong><span style="text-decoration: underline;">Le contrôle hôte</span></strong></p>
<p>Pour donner un peu de style à notre popup, nous allons créer un content contrôle personnalisé qui va se charger de wrapper la vue. Pour y parvenir, commencez par ajouter un nouvel item à votre projet de type Custom Control (WPF). Vous devriez voir dans l&#8217;arborescence du projet un fichier cs qui va contenir la logique de votre contrôle ainsi qu&#8217;un dossier Thèmes avec un fichier xaml de resource nommé Generic.xaml qui contient l&#8217; UI.</p>
<p>Fichier code:</p>
<pre class="code">[<span style="color: #2b91af;">TemplateVisualState</span>(Name = OpenState, GroupName = ModalState)]
<span style="color: blue;">public class </span><span style="color: #2b91af;">Host </span>: <span style="color: #2b91af;">ContentControl
</span>{
    <span style="color: blue;">const string </span>OpenState = <span style="color: #a31515;">"OpenState"</span>;
    <span style="color: blue;">const string </span>ModalState = <span style="color: #a31515;">"ModalStates"</span>;

    <span style="color: blue;">static </span>Host()
    {
        DefaultStyleKeyProperty
            .OverrideMetadata(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Host</span>),
            <span style="color: blue;">new </span><span style="color: #2b91af;">FrameworkPropertyMetadata</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Host</span>)));
    }

    <span style="color: blue;">public void </span>Show()
    {
        <span style="color: #2b91af;">VisualStateManager</span>.GoToState(<span style="color: blue;">this</span>, OpenState, <span style="color: blue;">false</span>);
    }

    <span style="color: blue;">public string </span>Title
    {
        <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>(<span style="color: blue;">string</span>)GetValue(TitleProperty); }
        <span style="color: blue;">set </span>{ SetValue(TitleProperty, <span style="color: blue;">value</span>); }
    }

    <span style="color: blue;">public static readonly </span><span style="color: #2b91af;">DependencyProperty </span>TitleProperty =
        <span style="color: #2b91af;">DependencyProperty</span>.Register(<span style="color: #a31515;">"Title"</span>,
        <span style="color: blue;">typeof</span>(<span style="color: blue;">string</span>), <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Host</span>), <span style="color: blue;">null</span>);

}</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;">Dans notre code, plusieurs points:</span></p>
<ul>
<li>
<div>Le contrôle hérite de ContentControl</div>
</li>
<li>
<div>Nous utilisons l’attribut TemplateVisualState pour dire que le contrôle peut être dans un état OpenState. Cet état doit se trouver dans le ControlTemplate qui lui même est situé dans le generic.xaml.</div>
</li>
<li>
<div>Une méthode Show que l’on va appeler plus tard pour afficher le contenu présent dans le contrôle hôte. Notez au passage qu’avec WPF 4, il y a l’ajout du VisualStateManager.</div>
</li>
<li>
<div>Une dependency property title, pour comme son nom l’indique, spécifier un titre dans notre popup.</div>
</li>
</ul>
<p><span style="text-decoration: underline;">Côté UI, quelque chose de très simple pour la démo:</span></p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">Style </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">local</span><span style="color: blue;">:</span><span style="color: red;">Host</span><span style="color: blue;">}"&gt;
  &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Background" </span><span style="color: red;">Value</span><span style="color: blue;">="#AA000000" /&gt;
    &lt;</span><span style="color: #a31515;">Setter </span><span style="color: red;">Property</span><span style="color: blue;">="Template"&gt;
      &lt;</span><span style="color: #a31515;">Setter.Value</span><span style="color: blue;">&gt;
       &lt;</span><span style="color: #a31515;">ControlTemplate </span><span style="color: red;">TargetType</span><span style="color: blue;">="{</span><span style="color: #a31515;">x</span><span style="color: blue;">:</span><span style="color: #a31515;">Type </span><span style="color: red;">local</span><span style="color: blue;">:</span><span style="color: red;">Host</span><span style="color: blue;">}"&gt;
         &lt;</span><span style="color: #a31515;">Grid</span><span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">VisualStateManager.VisualStateGroups</span><span style="color: blue;">&gt;
           &lt;</span><span style="color: #a31515;">VisualStateGroup </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="ModalStates" &gt;
            &lt;</span><span style="color: #a31515;">VisualState </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="OpenState"&gt;
                &lt;</span><span style="color: #a31515;">Storyboard </span><span style="color: red;">BeginTime</span><span style="color: blue;">="0:0:0"
                 </span><span style="color: red;">Storyboard.TargetName</span><span style="color: blue;">="ModalBorder"
                 </span><span style="color: red;">Storyboard.TargetProperty</span><span style="color: blue;">="Opacity" &gt;
                 &lt;</span><span style="color: #a31515;">DoubleAnimation  </span><span style="color: red;">To</span><span style="color: blue;">="1" </span><span style="color: red;">Duration</span><span style="color: blue;">="0:0:1"/&gt;
                &lt;/</span><span style="color: #a31515;">Storyboard</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">VisualState</span><span style="color: blue;">&gt;
           &lt;/</span><span style="color: #a31515;">VisualStateGroup</span><span style="color: blue;">&gt;
          &lt;/</span><span style="color: #a31515;">VisualStateManager.VisualStateGroups</span><span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">Border </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="ModalBorder"
                  </span><span style="color: red;">Margin</span><span style="color: blue;">="40" </span><span style="color: red;">Opacity</span><span style="color: blue;">="0"
                </span><span style="color: red;">CornerRadius</span><span style="color: blue;">="20" </span><span style="color: red;">Background</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Background</span><span style="color: blue;">}"&gt;
             &lt;</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
              &lt;</span><span style="color: #a31515;">TextBlock </span><span style="color: red;">Margin</span><span style="color: blue;">="20,0,0,0" </span><span style="color: red;">FontSize</span><span style="color: blue;">="20"
                         </span><span style="color: red;">Text</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Title</span><span style="color: blue;">}"
                         </span><span style="color: red;">Foreground</span><span style="color: blue;">="White"/&gt;
              &lt;</span><span style="color: #a31515;">ContentPresenter </span><span style="color: red;">Content</span><span style="color: blue;">="{</span><span style="color: #a31515;">TemplateBinding </span><span style="color: red;">Content</span><span style="color: blue;">}"  /&gt;
             &lt;/</span><span style="color: #a31515;">StackPanel</span><span style="color: blue;">&gt;
           &lt;/</span><span style="color: #a31515;">Border</span><span style="color: blue;">&gt;
         &lt;/</span><span style="color: #a31515;">Grid</span><span style="color: blue;">&gt;
       &lt;/</span><span style="color: #a31515;">ControlTemplate</span><span style="color: blue;">&gt;
     &lt;/</span><span style="color: #a31515;">Setter.Value</span><span style="color: blue;">&gt;
   &lt;/</span><span style="color: #a31515;">Setter</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">Style</span><span style="color: blue;">&gt;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Ce code xaml se trouve dans le generic.xaml. On y renseigne le style complet de notre contrôle. Nous y mettons simplement un border dont le background a une valeur par défaut de #AA000000, mais il est modifiable via les propriétés du contrôle. Enfin, nous avons une storyboard dans le VisualState “OpenState” déclenché via le VisualStateManager dans le fichier de code ci-dessus pour modifier l’opacité du ContentPresenter.</p>
<p><strong>Helper</strong></p>
<p>Afin de pouvoir utiliser notre modal popup, nous allons créer une classe Helper dont le rôle est via une propriété attachée de récupérer une IModalView donnée par le ViewModel et de l’injecter dans le contrôle host, qui à son tour est ajouté comme enfant du panel sur lequel la propriété attachée est utilisée.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">ModalHelper
   </span>{
       <span style="color: blue;">public static </span><span style="color: #2b91af;">IModalView </span>GetModalViewContent(<span style="color: #2b91af;">DependencyObject </span>obj)
       {
           <span style="color: blue;">return </span>(<span style="color: #2b91af;">IModalView</span>)obj.GetValue(ModalViewContentProperty);
       }

       <span style="color: blue;">public static void </span>SetModalViewContent(<span style="color: #2b91af;">DependencyObject </span>obj,
           <span style="color: #2b91af;">IModalView </span>value)
       {
           obj.SetValue(ModalViewContentProperty, value);
       }

       <span style="color: blue;">public static readonly </span><span style="color: #2b91af;">DependencyProperty </span>ModalViewContentProperty =
           <span style="color: #2b91af;">DependencyProperty</span>.RegisterAttached(<span style="color: #a31515;">"ModalViewContent"</span>,
           <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IModalView</span>), <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ModalHelper</span>),
           <span style="color: blue;">new </span><span style="color: #2b91af;">UIPropertyMetadata</span>(
               <span style="color: blue;">new </span><span style="color: #2b91af;">PropertyChangedCallback</span>(OnModaViewChanged)));

       <span style="color: blue;">private static </span><span style="color: #2b91af;">Panel </span>container;

       <span style="color: blue;">private static void </span>OnModaViewChanged(<span style="color: #2b91af;">DependencyObject </span>d,
           <span style="color: #2b91af;">DependencyPropertyChangedEventArgs </span>e)
       {
           <span style="color: green;">//Contrôle dans lequel, on injecte le host
           </span>container = d <span style="color: blue;">as </span><span style="color: #2b91af;">Panel</span>;
           <span style="color: #2b91af;">IModalView </span>view = e.NewValue <span style="color: blue;">as </span><span style="color: #2b91af;">IModalView</span>;

           <span style="color: blue;">if </span>(container != <span style="color: blue;">null </span>&amp;&amp; view != <span style="color: blue;">null</span>)
           {
               <span style="color: #2b91af;">Host </span>host = <span style="color: blue;">new </span><span style="color: #2b91af;">Host</span>();
               host.Content = view;
               host.Width = container.ActualWidth;
               host.Height = container.ActualHeight;
               host.Title = view.Title;
               container.Children.Add(host);

               host.Loaded += (s, ev) =&gt; { host.Show(); };
               host.Show();

               view.closeEvent += () =&gt;
                   {
                       <span style="color: blue;">if </span>(container != <span style="color: blue;">null</span>)
                           container.Children.Remove(host);
                   };
           }
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Du côté du ViewModel principal de l&#8217;application, nous devons ajouter une propriété chargée de stocker à un instant t une vue modale, donc de type IModalView.</p>
<p>Pour simplifier la démo, notre vue modale va être injectée directement dans le constructeur. Bien entendu dans la réalité, vous pourrez créer des commandes, pour déclencher l’affichage d’une vue modale quelconque.</p>
<pre class="code"><span style="color: blue;">public </span>MainViewModel(<span style="color: #2b91af;">IMainView </span>view,
         <span style="color: #2b91af;">IModalView </span>modalView)
     {
         <span style="color: blue;">if </span>(view == <span style="color: blue;">null</span>)
             <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"view"</span>);

         <span style="color: blue;">if </span>(modalView == <span style="color: blue;">null</span>)
             <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"modalView"</span>);

         <span style="color: blue;">this</span>.View = view;
         <span style="color: blue;">this</span>.View.ViewModel = <span style="color: blue;">this</span>;

         <span style="color: blue;">this</span>.ModalView = modalView;
     }

     <span style="color: blue;">private </span><span style="color: #2b91af;">IModalView </span>modalView;
     <span style="color: blue;">public </span><span style="color: #2b91af;">IModalView </span>ModalView
     {
         <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>modalView; }
         <span style="color: blue;">set
         </span>{
             modalView = <span style="color: blue;">value</span>;
             OnNotify(<span style="color: #a31515;">"ModalView"</span>);
         }

     }</pre>
<p> </p>
<p>Dès que la valeur de ModalView est modifiée, la vue est notifiée via le OnNotify. Le callback de notre helper est alors appelé pour la création et l’affichage de la vue.</p>
<p>Si vous avez fait attention, il y  avait également un event closeEvent dans l’interface  IModalView. Je vous laisse le choix de l’implémenter  ou non. Il serait peut mieux de définir cette action au niveau du host lui même, plutôt que sur chaque vue modal.</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles319F43D/image5.png"><img style="display: inline; border: 0px;" title="image_thumb7" src="http://blog.experida.fr/wp-content/uploads/2010/06/image_thumb7.png" border="0" alt="image_thumb7" width="552" height="351" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/22/simuler-une-modal-popup-avec-mvvm-et-wpf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RIA Services &#8211; Cr&#233;ation d&#8217;un DomainService testable</title>
		<link>http://blog.experida.fr/2010/05/18/ria-services-cration-dun-domainservice-testable/</link>
		<comments>http://blog.experida.fr/2010/05/18/ria-services-cration-dun-domainservice-testable/#comments</comments>
		<pubDate>Tue, 18 May 2010 19:39:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[RiaServices]]></category>
		<category><![CDATA[Silverlight4]]></category>
		<category><![CDATA[UnitTest]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/18/ria-services-cration-dun-domainservice-testable/</guid>
		<description><![CDATA[Avec les RIA Services, la création d’un DomainService permet d’exposer un ensemble de données au client. Je vous propose de voir dans ce billet , comment rendre le code de ce DomainService Testable Unitairement. Prenons un cas simple. Nous venons de créer un fichier dbml contenant plusieurs entités: T_Logement_Log, T_Type_Logement, T_Ville_Vl. Comment récupérer les données. [...]]]></description>
			<content:encoded><![CDATA[<p>Avec les RIA Services, la création d’un DomainService permet d’exposer un ensemble de données au client. Je vous propose de voir dans ce billet , comment rendre le code de ce DomainService Testable Unitairement.</p>
<p>Prenons un cas simple. Nous venons de créer un fichier dbml contenant plusieurs entités: T_Logement_Log, T_Type_Logement, T_Ville_Vl.</p>
<p>Comment récupérer les données. La première solution qui pourrait vous venir à l’idée est de créer une méthode GetLogements par exemple, puis de créer dans son corps, une instance du datacontext pour y effectuer une requête LTS (LinqToSQL). Le problème en codant ainsi, c’est que nous avons une dépendance sur le model. Si nous réalisons un test unitaire de la méthode GetLogements et qu’une exception est levée dans le model, le test unitaire va échouer. En l’état, la méthode n’est pas testable. Il nous faut supprimer cette dépendance sur le model.</p>
<p><span id="more-38"></span></p>
<p>Une solution possible, est d’accéder au model par une interface. Ainsi , nous pouvons avoir dans notre code une implémentation correspondant au model réel et une implémentation “fausse” lors des tests unitaires, mais dont on est certains qu’elle nous retourne un résultat connu.</p>
<p>Pour que notre Service utilise la bonne instance, nous allons utiliser Unity qui se chargera de faire la résolution de type en fonction des paramètres qu’on aura précisé dans le web.config.</p>
<p><span style="text-decoration: underline;"><strong>Commençons par créer l’interface:</strong></span></p>
<p>Nous voulons que chaque classe implémentant l’interface soit une abstraction de notre Model, et qui puisse fonctionner avec LinqToSql, mais aussi avec LinqToEntities, d’où la proposition suivante, avec T le type d’objet sur lequel on travaille et TContext le contexte de données concerné.</p>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IRepository</span>&lt;T,TContext&gt;
  {
      <span style="color: #2b91af;">IQueryable</span>&lt;T&gt; Query();
      <span style="color: #2b91af;">IQueryable</span>&lt;T&gt; Query(<span style="color: #2b91af;">DataLoadOptions </span>option);
      <span style="color: blue;">void </span>Add(T entity);
      <span style="color: blue;">void </span>Remove(T entity);
      <span style="color: blue;">void </span>Attach(T current, T original);
      <span style="color: blue;">void </span>Attach(T current);
      <span style="color: blue;">void </span>SubmitChanges();
  }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;"><strong>Créons maintenant une classe LinqToSqlRepository qui implémente cette interface:</strong></span></p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">LinqToSqlRepository</span>&lt;T, TContext&gt; : <span style="color: #2b91af;">IRepository</span>&lt;T, TContext&gt;
      <span style="color: blue;">where </span>T : <span style="color: blue;">class
      where </span>TContext : <span style="color: #2b91af;">DataContext
  </span>{
      <span style="color: blue;">private </span><span style="color: #2b91af;">DataContext </span>context;

      <span style="color: blue;">public </span>LinqToSqlRepository()
      {
          <span style="color: blue;">this</span>.context = (<span style="color: #2b91af;">DataContext</span>)<span style="color: #2b91af;">Activator
              </span>.CreateInstance(<span style="color: blue;">typeof</span>(TContext));
      }

      <span style="color: blue;">#region </span>IRepository&lt;T&gt; Members

      <span style="color: blue;">public </span><span style="color: #2b91af;">IQueryable</span>&lt;T&gt; Query()
      {
          <span style="color: blue;">return this</span>.context.GetTable&lt;T&gt;();
      }

      <span style="color: blue;">public </span><span style="color: #2b91af;">IQueryable</span>&lt;T&gt; Query(<span style="color: #2b91af;">DataLoadOptions </span>option)
      {
          <span style="color: blue;">this</span>.context.LoadOptions = option;
          <span style="color: blue;">return this</span>.context.GetTable&lt;T&gt;();
      }

      <span style="color: blue;">public void </span>Add(T entity)
      {
          <span style="color: blue;">this</span>.context.GetTable&lt;T&gt;().InsertOnSubmit(entity);
      }

      <span style="color: blue;">public void </span>Remove(T entity)
      {
          <span style="color: blue;">this</span>.context.GetTable&lt;T&gt;().DeleteOnSubmit(entity);
      }

      <span style="color: blue;">public void </span>Attach(T current, T original)
      {
          <span style="color: blue;">this</span>.context.GetTable&lt;T&gt;().Attach(current, original);
      }

      <span style="color: blue;">public void </span>Attach(T current)
      {
          <span style="color: blue;">this</span>.context.GetTable&lt;T&gt;().Attach(current);
      }

      <span style="color: blue;">public void </span>SubmitChanges()
      {
          <span style="color: blue;">this</span>.context.SubmitChanges();
      }

      <span style="color: blue;">#endregion
  </span>}</pre>
<p>Comme vous pouvez le remarquer TContext est ici de type DataContext car nous sommes dans le cadre de LinqToSql. Nous retrouvons les méthodes présentes dans notre interface avec diverses opérations faites sur le contexte.</p>
<p>Maintenant que nous avons notre interface et une implémentation, nous allons adapter notre DomainService afin qu’il n’y ait pas de dépendance. Je rappelle que les instances de IRepository&lt;T,TContext&gt;, vont être injectées par Unity. Nous allons donc les passer au constructeur.</p>
<pre class="code"><span style="color: blue;">   private readonly
     </span><span style="color: #2b91af;">IRepository</span>&lt;<span style="color: #2b91af;">T_Logements_Log</span>, <span style="color: #2b91af;">ModelDataContext</span>&gt; repositoryLogement;
   <span style="color: blue;">private readonly
     </span><span style="color: #2b91af;">IRepository</span>&lt;<span style="color: #2b91af;">T_Types_Logement</span>, <span style="color: #2b91af;">ModelDataContext</span>&gt; repositoryTypeLogement;
   <span style="color: blue;">private readonly
     </span><span style="color: #2b91af;">IRepository</span>&lt;<span style="color: #2b91af;">T_Ville_Vl</span>, <span style="color: #2b91af;">ModelDataContext</span>&gt; repositoryVille;

   <span style="color: blue;">public </span>ImmoService(
    <span style="color: #2b91af;">IRepository</span>&lt;<span style="color: #2b91af;">T_Logements_Log</span>, <span style="color: #2b91af;">ModelDataContext</span>&gt; repositoryLogement,
    <span style="color: #2b91af;">IRepository</span>&lt;<span style="color: #2b91af;">T_Types_Logement</span>, <span style="color: #2b91af;">ModelDataContext</span>&gt; repositoryTypeLogement,
    <span style="color: #2b91af;">IRepository</span>&lt;<span style="color: #2b91af;">T_Ville_Vl</span>,<span style="color: #2b91af;">ModelDataContext</span>&gt; repositoryVille)
       {
           <span style="color: blue;">if </span>(repositoryLogement == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new
                   </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"repositoryLogement"</span>);

           <span style="color: blue;">if </span>(repositoryTypeLogement == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new
                   </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"repositoryTypeLogement"</span>);

           <span style="color: blue;">if </span>(repositoryVille == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new
                   </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"repositoryVille"</span>);

           <span style="color: blue;">this</span>.repositoryLogement = repositoryLogement;
           <span style="color: blue;">this</span>.repositoryTypeLogement = repositoryTypeLogement;
           <span style="color: blue;">this</span>.repositoryVille = repositoryVille;
       }</pre>
<p><a href="http://11011.net/software/vspaste"></a>Nous vérifions seulement que les instances ne sont pas null, puis nous les assignons à des variables qui au passage sont en readonly et donc non modifiables en dehors du constructeur.</p>
<p><span style="text-decoration: underline;"><strong>En reprenant la méthode GetLogements citée plus haut cela donne:</strong></span></p>
<pre class="code">[<span style="color: #2b91af;">Query</span>]
       <span style="color: blue;">public </span><span style="color: #2b91af;">IQueryable</span>&lt;<span style="color: #2b91af;">T_Logements_Log</span>&gt; GetLogements()
       {
           <span style="color: blue;">return </span>repositoryLogement.Query();
       }</pre>
<p> </p>
<p><span style="text-decoration: underline;"><strong>Pour les Logements de type appartement, on aurait le code:</strong></span></p>
<pre class="code">[<span style="color: #2b91af;">Query</span>]
    <span style="color: blue;">public </span><span style="color: #2b91af;">IQueryable</span>&lt;<span style="color: #2b91af;">T_Logements_Log</span>&gt; GetLogementsByAppartement()
    {
        <span style="color: blue;">return </span>repositoryLogement.Query()
            .Where(l =&gt; l.T_Types_Logement.Tlog_Code == <span style="color: #a31515;">"APP"</span>)
            .OrderBy(l =&gt; l.Log_Id);
    }</pre>
<p>Point important à noter, notre DomainService hérite de DomainService. Pour que les différentes instances de IRepository&lt;T,TContext&gt; soient injectées, nous devons faire une résolution du type de notre DomainService. Par cette action Unity va regarder si il a dans son container des instances correspondant aux types passés au constructeur.</p>
<p>Pour y arriver nous allons créer une factory implémentant l’interface IDomainServiceFactory et l’assigner à la propriété statique Factory de la classe DomainService. Ainsi cette factory sera appelée pour créer le DomainService.</p>
<p><span style="text-decoration: underline;"><strong>Détail de la factory:</strong></span></p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">DomainServiceFactory </span>: <span style="color: #2b91af;">IDomainServiceFactory
   </span>{
       [<span style="color: #2b91af;">Dependency</span>]
       <span style="color: blue;">public </span><span style="color: #2b91af;">IUnityContainer </span>Container { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }

       <span style="color: blue;">public </span><span style="color: #2b91af;">DomainService
           </span>CreateDomainService(<span style="color: #2b91af;">Type </span>domainServiceType,
           <span style="color: #2b91af;">DomainServiceContext </span>context)
       {
           <span style="color: blue;">var </span>service =  Container.Resolve(domainServiceType)
               <span style="color: blue;">as </span><span style="color: #2b91af;">DomainService</span>;
           service.Initialize(context);

           <span style="color: blue;">return </span>service;

       }

       <span style="color: blue;">public void </span>ReleaseDomainService(<span style="color: #2b91af;">DomainService </span>domainService)
       {
           <span style="color: blue;">if</span>(domainService != <span style="color: blue;">null</span>)
               domainService.Dispose();
       }
   }</pre>
<p>Remarquez dans le code ci-dessus la résolution du DomainService depuis son type, puis l’appelle de la méthode Initialize.</p>
<p>Dans notre exemple, l’assignation de la propriété est faite dans le global.asax</p>
<pre class="code"><span style="color: blue;">private </span><span style="color: #2b91af;">IUnityContainer </span>container;

      <span style="color: blue;">protected void </span>Application_Start(<span style="color: blue;">object </span>sender, <span style="color: #2b91af;">EventArgs </span>e)
      {
          <span style="color: blue;">this</span>.container = <span style="color: blue;">new </span><span style="color: #2b91af;">UnityContainer</span>();
          <span style="color: #2b91af;">UnityConfigurationSection </span>section =
              (<span style="color: #2b91af;">UnityConfigurationSection</span>)<span style="color: #2b91af;">ConfigurationManager
              </span>.GetSection(<span style="color: #a31515;">"unity"</span>);
          section.Containers.Default.Configure(<span style="color: blue;">this</span>.container);
          <span style="color: #2b91af;">DomainService</span>.Factory = <span style="color: blue;">this</span>.container
              .Resolve&lt;<span style="color: #2b91af;">DomainServiceFactory</span>&gt;();
      }</pre>
<ul>
<li>On créé une instance de UnityContainer</li>
<li>On récupère depuis le web.config la configuration des types pour que Unity puisse faire les résolutions.</li>
<li>On demande au container de faire la résolution du type DomainServiceFactory chargé de la création du DomainService</li>
</ul>
<p>Dernier point qu’il nous reste à voir, le web.config. Toute la configuration / Mapping des types est faite dans ce fichier</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">unity</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">typeAliases</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">typeAlias
        </span><span style="color: red;">alias</span><span style="color: blue;">=</span>"<span style="color: blue;">singleton</span>"
        <span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Microsoft.Practices.Unity.
        ContainerControlledLifetimeManager,Microsoft.Practices.Unity</span>"<span style="color: blue;">/&gt;
            &lt;</span><span style="color: #a31515;">typeAlias
        </span><span style="color: red;">alias</span><span style="color: blue;">=</span>"<span style="color: blue;">IRepository`2</span>"
        <span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Demo.Model.Repository.Contract.
        IRepository`2,Demo.Model.Repository.Contract</span>"<span style="color: blue;">/&gt;
        &lt;/</span><span style="color: #a31515;">typeAliases</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">containers</span><span style="color: blue;">&gt;
            &lt;</span><span style="color: #a31515;">container</span><span style="color: blue;">&gt;
                &lt;</span><span style="color: #a31515;">types</span><span style="color: blue;">&gt;
                    &lt;</span><span style="color: #a31515;">type </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">IRepository`2</span>"
                <span style="color: red;">mapTo</span><span style="color: blue;">=</span>"<span style="color: blue;">Demo.Model.Repository.LinqToSqlRepository`2,
                Demo.Model.Repository</span>"<span style="color: blue;">&gt;
                        &lt;</span><span style="color: #a31515;">lifetime </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">singleton</span>"<span style="color: blue;">/&gt;
                    &lt;/</span><span style="color: #a31515;">type</span><span style="color: blue;">&gt;
                &lt;/</span><span style="color: #a31515;">types</span><span style="color: blue;">&gt;
            &lt;/</span><span style="color: #a31515;">container</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">containers</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">unity</span><span style="color: blue;">&gt;</span></pre>
<p>Après lecture du global.asax, on peut remarquer que la configuration est récupérée depuis une section nommée unity. Cette section contient deux parties.</p>
<p><strong>Les alliasses</strong>, qui comme le nom l’indique permettent d’attribuer un nom à un type. Cela permet de simplifier l’écriture de la configuration des containers par la suite. Ici, nous en avons créé deux.</p>
<ul>
<li>Le premier pour le type singleton / instance unique</li>
<li>Le second pour notre Interface. Notez que comme il s’agit d’une interface générique, je dois ajouter à la fin du nom de l’interface une quote, ainsi que le nombre 2 qui représente le nombre de paramètres génériques.</li>
</ul>
<p><strong>Le container </strong>dans lequel on créé nos mappings. Ici on peut voir que pour notre Interface on assigne le type générique LinqToSqlRepository ce qui aura pour conséquence lors de l’injection de créer une instance de LinqToSqlRepository. Notez également la présence de l’attribut lifetime qui a pour valeur singleton, l’alias créé plus haut. LinqToSqlRepository sera donc instancié une seul fois. Chaque demande de résolution va renvoyer la même instance.</p>
<p>Voilà il ne vous reste plus qu’à créer un mock pour effectuer vos tests unitaires.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/18/ria-services-cration-dun-domainservice-testable/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mise en place du pattern MVVM + Unity dans une application WPF</title>
		<link>http://blog.experida.fr/2010/05/15/mise-en-place-du-pattern-mvvm-unity-dans-une-application-wpf/</link>
		<comments>http://blog.experida.fr/2010/05/15/mise-en-place-du-pattern-mvvm-unity-dans-une-application-wpf/#comments</comments>
		<pubDate>Sat, 15 May 2010 19:42:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[MVVM]]></category>
		<category><![CDATA[Tests]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/15/mise-en-place-du-pattern-mvvm-unity-dans-une-application-wpf/</guid>
		<description><![CDATA[Avant de voir comment implémenter MVVM et Unity dans une application WPF je vous propose de faire un bref rappel sur ce qu’ils représentent. MVVM est avant tout, une séparation des rôles. Il permet de rendre l’application testable car les trois entités que sont la View, le ViewModel et le Model sont trois entités indépendantes [...]]]></description>
			<content:encoded><![CDATA[<p>Avant de voir comment implémenter MVVM et Unity dans une application WPF je vous propose de faire un bref rappel sur ce qu’ils représentent.</p>
<p>MVVM est avant tout, une séparation des rôles. Il permet de rendre l’application testable car les trois entités que sont la <strong>View</strong>, le <strong>ViewModel</strong> et le<strong> Model </strong>sont trois entités indépendantes qui communiquent l’une avec l’autre. En enlevant la logique du code-behind de la vue et en la plaçant dans le <strong>ViewModel</strong> ou encore dans différents services, le designer peut se concentrer sur son cœur de métier à savoir la création de la <strong>View</strong>.</p>
<p><span id="more-42"></span></p>
<p>La vue est représentée par ce que nous avons à l’écran.</p>
<ul>
<li>Control</li>
<li>UserControl</li>
<li>Animations</li>
</ul>
<p>Tous ces éléments permettent une présentation de l’information à l’utilisateur.</p>
<p>La View communique avec le <strong>ViewModel</strong> via le Binding.</p>
<p>Le ViewModel est le composant qui:</p>
<ul>
<li>Joue le rôle d’adaptateur entre le modèle et la vue</li>
<li>Doit fournir les données à la vue</li>
<li>Expose des commandes / des propriétés publiques que la vue utilise via le Binding pour interagir avec le modèle</li>
<li>Implémente l’interface INotifyPropertyChanged pour notifier la vue lors d’un changement dans le ViewModel</li>
</ul>
<p>Enfin le <strong>Model</strong> est constitué d’entités représentant les données</p>
<p><a href="file:///C:/Users/alex/AppData/Local/Temp/WindowsLiveWriter1286139640/supfiles320703F/viewmodel4.jpg"><img style="display: inline; border: 0px;" title="viewmodel_thumb2" src="http://blog.experida.fr/wp-content/uploads/2010/06/viewmodel_thumb2.jpg" border="0" alt="viewmodel_thumb2" width="565" height="179" /></a></p>
<p>Une View et un ViewModel fonctionnent en paire.</p>
<p>Certaines personnes partent du principe que le code-behind ne doit contenir aucun code, cependant, j’ai pris pour habitude de définir un contrat pour la View, ainsi qu’un contrat pour le ViewModel, puis d’injecter la View dans le ViewModel. Enfin le ViewModel est assigné à la View et plus précisément à son DataContext via une propriété public dans le code-behind. Les deux parties ne se connaissent que par leur interface.</p>
<p>Venons en à Unity. Il s’agit d’un conteneur dans lequel nous enregistrons soit par code, soit par config, un mapping entre une class concrète et son interface ou sa base class.</p>
<p>Par exemple, dans le cas d’utilisation du pattern MVVM, tous les services référencés dans le ViewModel devront l’être par leur interface. Unity se chargera alors de regarder dans son dictionnaire interne si il possède une class concrète pour cette interface, levant une exception le cas échéant.</p>
<p>Le fait de passer par cette méthode supprime les dépendances. Si demain vous voulez changer votre DAL, vous pouvez développer la nouvelle et l’enregistrer dans unity sans vous soucier du ViewModel dès lors qu’elle respecte l’interface.</p>
<p>Moins de dépendances signifie aussi plus testable. Vous vous concentrés sur le contenu de la méthode à tester et non sur les services qui y sont appelés. Pour ces services vous devez créer des mocks et lors du test, nous considérons que ce qui se passe dans ces mocks ne doit pas faire échouer notre test.</p>
<p>Pour intégrer MVVM et unity dans votre application WPF, les étapes suivantes peuvent être réalisées:</p>
<p><span style="text-decoration: underline;">Ajout de Unity à votre projet </span></p>
<p>Commencez par ajouter une référence sur Unity en ajoutant la dll Microsoft.Practices.Unity</p>
<p><span style="text-decoration: underline;">Création de la View et du ViewModel</span></p>
<p>Partons sur des contrats simples pour l’exemple. La View référence le ViewModel par son interface et donne une méthode qui permet de la rendre visible. Le ViewModel ajoute une référence sur la View</p>
<pre class="code"><span style="color: blue;">public interface </span><span style="color: #2b91af;">IMainView
   </span>{
       <span style="color: #2b91af;">IMainViewModel </span>ViewModel { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
       <span style="color: blue;">void </span>ShowView();
   }

   <span style="color: blue;">public interface </span><span style="color: #2b91af;">IMainViewModel
   </span>{
       <span style="color: #2b91af;">IMainView </span>View { <span style="color: blue;">get</span>; }
   }</pre>
<p>Ensuite nous créons deux implémentations.</p>
<p>Pour le ViewModel, la View est injectée dans le ViewModel</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">MainViewModel </span>: <span style="color: #2b91af;">IMainViewModel
   </span>{
       <span style="color: blue;">public </span>MainViewModel(<span style="color: #2b91af;">IMainView </span>view)
       {
           <span style="color: blue;">if </span>(view == <span style="color: blue;">null</span>)
               <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"view"</span>);

           <span style="color: blue;">this</span>.View = view;
           <span style="color: blue;">this</span>.View.ViewModel = <span style="color: blue;">this</span>;
       }

       <span style="color: blue;">public </span><span style="color: #2b91af;">IMainView </span>View
       {
           <span style="color: blue;">get</span>;
           <span style="color: blue;">private set</span>;
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Généralement les services nécessaires à la construction du ViewModel sont injectés par constructeur et les autres par propriété.</p>
<p>Pour la view, on retrouve notamment notre propriété avec l’interface du ViewModel</p>
<pre class="code"><span style="color: blue;">public partial class </span><span style="color: #2b91af;">MainWindow </span>: <span style="color: #2b91af;">Window </span>, <span style="color: #2b91af;">IMainView
   </span>{
       <span style="color: blue;">public </span>MainWindow()
       {
           InitializeComponent();
       }

       <span style="color: blue;">public </span><span style="color: #2b91af;">IMainViewModel </span>ViewModel
       {
           <span style="color: blue;">get
           </span>{
               <span style="color: blue;">return </span>(<span style="color: #2b91af;">IMainViewModel</span>)<span style="color: blue;">this</span>.DataContext;
           }
           <span style="color: blue;">set
           </span>{
               <span style="color: blue;">this</span>.DataContext = <span style="color: blue;">value</span>;
           }
       }

       <span style="color: blue;">public void </span>ShowView()
       {
           <span style="color: blue;">this</span>.Show();
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p><span style="text-decoration: underline;">Création du BootSrapper.</span></p>
<p>Appelé depuis App.xaml.cs, il contient le code qui se charge de faire l’enregistrement des types dans Unity et de faire la résolution de la fenêtre principale.</p>
<p>Commençons par instancier Unity, puis ajoutons les mappings par code et config pour la démo.</p>
<p><span style="text-decoration: underline;">Par code</span></p>
<pre class="code"><span style="color: #2b91af;">IUnityContainer </span>unityContainer = <span style="color: blue;">new </span><span style="color: #2b91af;">UnityContainer</span>();
           unityContainer.RegisterType&lt;<span style="color: #2b91af;">IMainViewModel</span>, <span style="color: #2b91af;">MainViewModel</span>&gt;();
           unityContainer.RegisterType&lt;<span style="color: #2b91af;">IMainView</span>, <span style="color: #2b91af;">MainWindow</span>&gt;();</pre>
<p> </p>
<p><span style="text-decoration: underline;">Par configuration</span></p>
<p>Avant d’aller plus loin, vous devez ajouter une référence vers Microsoft.Practices.Unity.Configuration</p>
<p>puis modifier le bootstrapper</p>
<pre class="code"><span style="color: #2b91af;">IUnityContainer </span>unityContainer = <span style="color: blue;">new </span><span style="color: #2b91af;">UnityContainer</span>();
<span style="color: #2b91af;">UnityConfigurationSection </span>section =
    (<span style="color: #2b91af;">UnityConfigurationSection</span>)<span style="color: #2b91af;">ConfigurationManager</span>.GetSection(<span style="color: #a31515;">"unity"</span>);
section.Configure(unityContainer);</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>et faire les changements nécessaires dans votre app.config</p>
<pre class="code"><span style="color: blue;">&lt;</span><span style="color: #a31515;">configuration</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">configSections</span><span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">section </span><span style="color: red;">name</span><span style="color: blue;">=</span>"<span style="color: blue;">unity</span>"
     <span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
     Microsoft.Practices.Unity.Configuration</span>" <span style="color: blue;">/&gt;
  &lt;/</span><span style="color: #a31515;">configSections</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">unity</span><span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">containers</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">container</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">type </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">WpfApplication.IMainViewModel,WpfApplication</span>"
              <span style="color: red;">mapTo</span><span style="color: blue;">=</span>"<span style="color: blue;">WpfApplication.MainViewModel,WpfApplication</span>" <span style="color: blue;">/&gt;
        &lt;</span><span style="color: #a31515;">type </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">WpfApplication.IMainView,WpfApplication</span>"
              <span style="color: red;">mapTo</span><span style="color: blue;">=</span>"<span style="color: blue;">WpfApplication.MainWindow,WpfApplication</span>" <span style="color: blue;">/&gt;
      &lt;/</span><span style="color: #a31515;">container</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">containers</span><span style="color: blue;">&gt;
  &lt;/</span><span style="color: #a31515;">unity</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">configuration</span><span style="color: blue;">&gt;
</span></pre>
<p>Il s’agit ici d’une configuration simple. Unity vous permet également d’ajouter des paramètres pour spécifier que votre type est un singleton, que vous souhaitez passer un paramètre à votre constructeur….. Je vous invite à aller voir sur le site officiel de Unity <a title="http://unity.codeplex.com/" href="http://unity.codeplex.com/">http://unity.codeplex.com/</a></p>
<p>Pour montrer la fenêtre principale, il vous suffit de demander à Unity de faire la résolution du ViewModel, puis d’appeler la méthode ShowView de la View.</p>
<pre class="code"><span style="color: #2b91af;">IMainViewModel </span>mainViewModel = unityContainer.Resolve&lt;<span style="color: #2b91af;">IMainViewModel</span>&gt;();
        mainViewModel.View.ShowView();</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Enfin pour terminer, il ne vous reste plus qu’à instancier le bootStrapper. N’oubliez pas de retirer le StartupUri dans le App.xaml</p>
<pre class="code"><span style="color: blue;">public partial class </span><span style="color: #2b91af;">App </span>: <span style="color: #2b91af;">Application
   </span>{
       <span style="color: blue;">protected override void </span>OnStartup(<span style="color: #2b91af;">StartupEventArgs </span>e)
       {
           <span style="color: blue;">base</span>.OnStartup(e);

           <span style="color: #2b91af;">BootStrapper </span>boot = <span style="color: blue;">new </span><span style="color: #2b91af;">BootStrapper</span>();
           boot.Load();
       }
   }</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/15/mise-en-place-du-pattern-mvvm-unity-dans-une-application-wpf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Glissez des fichiers dans votre application Silverlight depuis l&#8217;explorateur windows</title>
		<link>http://blog.experida.fr/2010/05/08/glissez-des-fichiers-dans-votre-application-silverlight-depuis-lexplorateur-windows/</link>
		<comments>http://blog.experida.fr/2010/05/08/glissez-des-fichiers-dans-votre-application-silverlight-depuis-lexplorateur-windows/#comments</comments>
		<pubDate>Sat, 08 May 2010 19:46:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Drag]]></category>
		<category><![CDATA[Drop]]></category>
		<category><![CDATA[Silverlight4]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/08/glissez-des-fichiers-dans-votre-application-silverlight-depuis-lexplorateur-windows/</guid>
		<description><![CDATA[Depuis la version 4 de Silverlight, vous avez la possibilité de glisser un ou plusieurs fichiers depuis l’explorateur windows vers une application Silverlight. Nous allons voir ensemble comment procéder. Ce billet sera découpé en deux parties: La première utilisera un event handler créé dans le code behind pour répondre à l’event Drop Dans le second [...]]]></description>
			<content:encoded><![CDATA[<p>Depuis la version 4 de Silverlight, vous avez la possibilité de glisser un ou plusieurs fichiers depuis l’explorateur windows vers une application Silverlight. Nous allons voir ensemble comment procéder.</p>
<p><span style="text-decoration: underline;">Ce billet sera découpé en deux parties:</span></p>
<ol>
<li>
<div>La première utilisera un event handler créé dans le code behind pour répondre à l’event Drop</div>
</li>
<li>
<div>Dans le second cas nous verrons comment implémenter une Commande pour utiliser cette fonctionnalité dans une utilisation avec le pattern MVVM</div>
</li>
</ol>
<p> <span id="more-45"></span></p>
<p><span style="text-decoration: underline;"><strong> </strong></span></p>
<p><span style="text-decoration: underline;"><strong>1. Event Handler &#8211; CodeBehind</strong></span></p>
<p>Nous voulons une application dans laquelle nous avons la possibilité de glisser des images au format jpg.</p>
<p>La première chose à faire est d’ajouter <strong>AllowDrop=”True”, </strong>sur l’élément où l’on désire glisser le ou les fichiers. La seule contrainte ici est que l’élément soit un UIElement.</p>
<div>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">Grid </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="LayoutRoot" </span><span style="color: red;">AllowDrop</span><span style="color: blue;">="True" </span><span style="color: red;">Drop</span><span style="color: blue;">="LayoutRoot_Drop"&gt;
</span></pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Comme vous pouvez le remarquer nous devons également nous abonner à l’évènement Drop. Dans notre cas le handler se nomme LayoutRoot_Drop et se trouve dans le code behind de notre UserControl.</p>
<div>
<pre class="code"><span style="color: blue;">private void </span>LayoutRoot_Drop(<span style="color: blue;">object </span>sender, <span style="color: #2b91af;">DragEventArgs </span>e){}</pre>
</div>
<p><span style="text-decoration: underline;">Le handler prend deux paramètres:</span></p>
<ul>
<li>
<div>Le sender correpondant ici à notre Grid</div>
</li>
<li>
<div>Et un eventArgs <span style="color: #2b91af;">DragEventArgs </span>qui contient les données de DragAndDrop et notamment les informations sur les fichiers.</div>
</li>
</ul>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Via le <span style="color: #2b91af;">DragEventArgs</span>, nous récupérons un tableau de FileInfo qui permet de décrire les fichiers glissés dans l’application, dont notamment le nom de l’image et  l’extension sur laquelle nous appliquons un filtre pour ne récupérer que les images au format jpg.</p>
<pre class="code"><span style="color: #2b91af;">FileInfo</span>[] files = e.Data.GetData(<span style="color: #2b91af;">DataFormats</span>.FileDrop) <span style="color: blue;">as </span><span style="color: #2b91af;">FileInfo</span>[];</pre>
<pre class="code"><span style="color: blue;">if </span>(files != <span style="color: blue;">null</span>)
{
    <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>fileInfo <span style="color: blue;">in </span>files)
    {
        <span style="color: blue;">if </span>(fileInfo.Extension == <span style="color: #a31515;">".jpg"</span>)
        {
        }
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Avant d’aller plus loin, retournons dans le code xaml afin d’ajouter un contrôle pour afficher les images. Une simple ListBox est suffisante.</p>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">SelectionMode</span><span style="color: blue;">="Multiple" </span><span style="color: red;">HorizontalAlignment</span><span style="color: blue;">="Stretch"
   </span><span style="color: red;">VerticalAlignment</span><span style="color: blue;">="Stretch" </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="ImagesList" </span><span style="color: red;">Height</span><span style="color: blue;">="500" &gt;
   &lt;</span><span style="color: #a31515;">ListBox.ItemsPanel</span><span style="color: blue;">&gt;
     &lt;</span><span style="color: #a31515;">ItemsPanelTemplate</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">toolkit</span><span style="color: blue;">:</span><span style="color: #a31515;">WrapPanel </span><span style="color: red;">Orientation</span><span style="color: blue;">="Horizontal"  </span><span style="color: red;">UseLayoutRounding</span><span style="color: blue;">="True"
                      </span><span style="color: red;">Width</span><span style="color: blue;">="1024"  /&gt;
     &lt;/</span><span style="color: #a31515;">ItemsPanelTemplate</span><span style="color: blue;">&gt;
   &lt;/</span><span style="color: #a31515;">ListBox.ItemsPanel</span><span style="color: blue;">&gt;
   &lt;</span><span style="color: #a31515;">ListBox.ItemTemplate</span><span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
       &lt;</span><span style="color: #a31515;">Image </span><span style="color: red;">Width</span><span style="color: blue;">="200" </span><span style="color: red;">Stretch</span><span style="color: blue;">="Uniform" </span><span style="color: red;">Source</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding</span><span style="color: blue;">}" /&gt;
    &lt;/</span><span style="color: #a31515;">DataTemplate</span><span style="color: blue;">&gt;
   &lt;</span><span style="color: #a31515;">ListBox.ItemTemplate</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">ListBox</span><span style="color: blue;">&gt;
<span style="background-color: #ffffff; font-family: Tahoma; color: #000000;"> </span></span></pre>
<p>Nous commençons par lui donner un nom pour y accéder depuis le code behind: <strong>ImageList</strong></p>
<p>Au niveau du <strong>ItemsPanelTemplate</strong>, nous mettons un <strong>WrapPanel </strong>provenant du toolkit silverlight, pour que les éléments retournent automatiquement à la ligne une fois la largeur maximale du composant atteinte.</p>
<p>Enfin, nous modifions le DataTemplate pour indiquer que chacune de nos images aura une largeur maximum de 200, tout en gardant une taille uniforme.</p>
<p>Pour chaque FileInfo, nous allons créer un BitmapImage et l’ajouter dans une collection que l’on va assigner à la propriété ItemsSource de notre ListBox.</p>
<div>
<pre class="code"><span style="color: blue;">using </span>(<span style="color: blue;">var </span>fileStream = fileInfo.OpenRead())
{
    <span style="color: blue;">var </span>bitmapImage = <span style="color: blue;">new </span><span style="color: #2b91af;">BitmapImage</span>();
    bitmapImage.SetSource(fileStream);
    ImagesCollection.Add(bitmapImage);
    fileStream.Close();
}</pre>
</div>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><a href="http://11011.net/software/vspaste"></a>La collection est de type ObservableCollection. L’avantage d’utiliser ce type de collection est qu’elle va notifier l’interface, dès  qu’une nouvelle BitmapImage est ajoutée ou supprimée.</p>
<p>Glissez quelques images de votre explorer et vous devriez obtenir le résultat suivant dans votre navigateur web</p>
<p><a href="http://www.silverlightwpf.fr/image.axd?picture=Capture.jpg"><img style="display: inline; border-width: 0px;" title="Capture" src="http://www.silverlightwpf.fr/image.axd?picture=Capture_thumb.jpg" border="0" alt="Capture" width="540" height="214" /></a></p>
<p><span style="text-decoration: underline;">2. Avec MVVM</span></p>
<p>Nous allons partir du principe que vous avez déjà mis en place le pattern MVVM dans votre application. Le but ici n’est pas d’expliquer à quoi sert et comment marche MVVM, ça serait hors sujet, mais plutôt de montrer comment utiliser le Drop dans ce cas d’utilisation.</p>
<p>Silverlight 4 implémente maintenant de manière native la gestion des commandes sur les éléments comme le Button.</p>
<p>Cependant nous avons ici un besoin spécifique, qui est le déclenchement de la commande dès qu’un ou des éléments sont posés sur notre Grid.</p>
<p>Une solution possible serait d’étendre le Grid actuel, en lui donnant la possibilité de déclencher une commande lors d’un Drop. Le problème avec ce model, c’est que pour chaque contrôle où vous souhaitez exécuter une commande Drop, vous devez l’étendre. Vous allez vite vous retrouver avec un nombre important de contrôles dans votre projet.</p>
<p>Deuxième solution: utiliser le MVVM Light Toolkit de Laurent Bugnion <a title="http://www.galasoft-lb.ch/mvvm/getstarted/" href="http://www.galasoft-lb.ch/mvvm/getstarted/">http://www.galasoft-lb.ch/mvvm/getstarted/</a>, qui met à notre disposition un EventToCommand behavior. Voici le lien vers son tutorial: <a title="http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx" href="http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx">http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx</a>. Le principe de base c’est de pouvoir spécifier pour un contrôle donné, l’event qui va jouer le rôle de trigger pour la commande.</p>
<p>Pour notre exemple, nous allons nous tourner vers une solution fonctionnelle uniquement pour utiliser le Drop Event via une propriété attachée.</p>
<p><span style="text-decoration: underline;">Description de la solution:</span></p>
<p>Une commande est représentée par son interface <strong>ICommand</strong>, point de communication entre l’UI et le ViewModel lors de l’action utilisateur.  Un type de commande que l’on retrouve régulièrement est la <strong>DelegateCommand, </strong>également appelée <strong>RelayCommand. </strong>Son rôle est de déléguer la logique métier que l’on avait mis dans le code behind et donc dans la vue, dans une méthode du ViewModel. Cette méthode peut également contenir un argument, DragEventArgs dans notre cas.</p>
<p>Code de la DelegateCommand:</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">DelegateCommand </span>: <span style="color: #2b91af;">ICommand
   </span>{
       <span style="color: blue;">private </span><span style="color: #2b91af;">Func</span>&lt;<span style="color: blue;">object</span>, <span style="color: blue;">bool</span>&gt; canExecute;
       <span style="color: blue;">private </span><span style="color: #2b91af;">Action</span>&lt;<span style="color: blue;">object</span>&gt; executeAction;
       <span style="color: blue;">bool </span>canExecuteCache;

       <span style="color: blue;">public </span>DelegateCommand(<span style="color: #2b91af;">Action</span>&lt;<span style="color: blue;">object</span>&gt; executeAction)
           : <span style="color: blue;">this</span>(executeAction, <span style="color: blue;">null</span>)
       { }

       <span style="color: blue;">public </span>DelegateCommand(<span style="color: #2b91af;">Action</span>&lt;<span style="color: blue;">object</span>&gt; executeAction, <span style="color: #2b91af;">Func</span>&lt;<span style="color: blue;">object</span>, <span style="color: blue;">bool</span>&gt; canExecute)
       {
           <span style="color: blue;">this</span>.executeAction = executeAction;
           <span style="color: blue;">this</span>.canExecute = canExecute;
       }

       <span style="color: blue;">#region </span>ICommand Members
       <span style="color: blue;">public bool </span>CanExecute(<span style="color: blue;">object </span>parameter)
       {
           <span style="color: blue;">bool </span>temp = canExecute(parameter);
           <span style="color: blue;">if </span>(canExecuteCache != temp)
           {
               canExecuteCache = temp;
               <span style="color: blue;">if </span>(CanExecuteChanged != <span style="color: blue;">null</span>)
               {
                   CanExecuteChanged(<span style="color: blue;">this</span>, <span style="color: blue;">new </span><span style="color: #2b91af;">EventArgs</span>());
               }
           }

           <span style="color: blue;">return </span>canExecuteCache;
       }

       <span style="color: blue;">public event </span><span style="color: #2b91af;">EventHandler </span>CanExecuteChanged;

       <span style="color: blue;">public void </span>Execute(<span style="color: blue;">object </span>parameter)
       {
           executeAction(parameter);
       }
       <span style="color: blue;">#endregion
   </span>}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Maintenant que nous avons une ICommand, nous allons créer une class Helper avec une propriété attachée nommée DropCommandProperty.</p>
<div>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">DropHelper
</span>{
   <span style="color: blue;">public static </span><span style="color: #2b91af;">ICommand </span>GetDropCommand(<span style="color: #2b91af;">DependencyObject </span>obj)
   {
       <span style="color: blue;">return </span>(<span style="color: #2b91af;">ICommand</span>)obj.GetValue(DropCommandProperty);
   }

   <span style="color: blue;">public static void </span>SetDropCommand(<span style="color: #2b91af;">DependencyObject </span>obj, <span style="color: #2b91af;">ICommand </span>value)
   {
       obj.SetValue(DropCommandProperty, value);
   }

   <span style="color: blue;">public static readonly </span><span style="color: #2b91af;">DependencyProperty </span>DropCommandProperty =
     <span style="color: #2b91af;">DependencyProperty</span>.RegisterAttached(<span style="color: #a31515;">"DropCommand"</span>,
     <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ICommand</span>), <span style="color: blue;">typeof</span>(<span style="color: #2b91af;">DropHelper</span>),
     <span style="color: blue;">new </span><span style="color: #2b91af;">PropertyMetadata</span>(<span style="color: blue;">new </span><span style="color: #2b91af;">PropertyChangedCallback</span>(DropCommandChanged)));

   <span style="color: blue;">private static void
    </span>DropCommandChanged(<span style="color: #2b91af;">DependencyObject </span>d,
    <span style="color: #2b91af;">DependencyPropertyChangedEventArgs </span>e)
      {
       <span style="color: #2b91af;">UIElement </span>element = d <span style="color: blue;">as </span><span style="color: #2b91af;">UIElement</span>;

       <span style="color: blue;">if </span>(element == <span style="color: blue;">null</span>)
         <span style="color: blue;">throw new </span><span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Expected UIElement Type"</span>);

       <span style="color: blue;">if </span>(!element.AllowDrop)
         <span style="color: blue;">throw new </span><span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"AllowDrop Property must be equal to true"</span>);
         element.Drop += (s, ev) =&gt;
         {
           <span style="color: #2b91af;">ICommand </span>cmd = e.NewValue <span style="color: blue;">as </span><span style="color: #2b91af;">ICommand</span>;

               <span style="color: blue;">if </span>(cmd != <span style="color: blue;">null</span>)
                   cmd.Execute(ev);
         };
      }
  }</pre>
</div>
<p>Notez qu’on ajoute une méthode callback DropCommandChanged, de manière à vérifier que la commande est utilisée sur un UIElement et que la propriété AllowDrop a bien été mise à true. On s’abonne également sur l’évènement Drop qui une fois déclenché va exécuter la commande en passant en paramètre le DragEventArgs contenant les données de DragAndDrop.</p>
<p>Dans la pratique pour l’utiliser, vous avez deux choses à faire.</p>
<p>Modifier votre ViewModel de manière à ce qu’il fournisse une propriété retournant un ICommand et une méthode private, appelée suite à l’exécution de la commande avec exactement le même code que ce qu’on avait précédemment dans le code behind. Ne pas oublier également d’ajouter une ObservableCollection afin que la ListBox se Binde directement dessus.</p>
<pre class="code"><span style="color: blue;">public class </span><span style="color: #2b91af;">HomeViewModel
</span>{
    <span style="color: blue;">private </span><span style="color: #2b91af;">ICommand </span>dropCommand;

    <span style="color: blue;">public </span>HomeViewModel()
    {
    }

    <span style="color: blue;">public </span><span style="color: #2b91af;">ICommand </span>DropCommand
    {
        <span style="color: blue;">get
        </span>{
            <span style="color: blue;">if </span>(dropCommand == <span style="color: blue;">null</span>)
                dropCommand =
                    <span style="color: blue;">new </span><span style="color: #2b91af;">DelegateCommand</span>(param =&gt; Drop(param <span style="color: blue;">as </span><span style="color: #2b91af;">DragEventArgs</span>));

            <span style="color: blue;">return </span>dropCommand;
        }
    }

    <span style="color: blue;">private </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">BitmapImage</span>&gt; imagesCollection =
        <span style="color: blue;">new </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">BitmapImage</span>&gt;();
    <span style="color: blue;">public </span><span style="color: #2b91af;">ObservableCollection</span>&lt;<span style="color: #2b91af;">BitmapImage</span>&gt; ImagesCollection
    {
        <span style="color: blue;">get </span>{ <span style="color: blue;">return </span>imagesCollection; }
    }

    <span style="color: blue;">private void </span>Drop(<span style="color: #2b91af;">DragEventArgs </span>e)
    {
        <span style="color: blue;">if </span>(e == <span style="color: blue;">null</span>)
            <span style="color: blue;">throw new </span><span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"e"</span>);
        <span style="color: blue;">if </span>(e.Data != <span style="color: blue;">null</span>)
        {
     <span style="color: #2b91af;">FileInfo</span>[] files = e.Data.GetData(<span style="color: #2b91af;">DataFormats</span>.FileDrop) <span style="color: blue;">as </span><span style="color: #2b91af;">FileInfo</span>[];

               <span style="color: blue;">if </span>(files != <span style="color: blue;">null</span>)
               {
                   <span style="color: blue;">foreach </span>(<span style="color: blue;">var </span>fileInfo <span style="color: blue;">in </span>files)
                   {
                       <span style="color: blue;">if </span>(fileInfo.Extension == <span style="color: #a31515;">".jpg"</span>)
                       {

                           <span style="color: blue;">using </span>(<span style="color: blue;">var </span>fileStream = fileInfo.OpenRead())
                           {

                               <span style="color: blue;">var </span>bitmapImage = <span style="color: blue;">new </span><span style="color: #2b91af;">BitmapImage</span>();
                               bitmapImage.SetSource(fileStream);

                               ImagesCollection.Add(bitmapImage);

                               fileStream.Close();
                           }
                       }
                   }
               }
           }
       }
   }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Puis, modifier le code XAML de votre page en y ajoutant une référence vers la librairie contenant le helper, ici le projet courant.</p>
<pre class="code">  <span style="color: red;">xmlns</span><span style="color: blue;">:</span><span style="color: red;">helper</span><span style="color: blue;">="clr-namespace:FileDrop"
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Et en faisant le Binding sur la commande et sur la collection de BitmapImage</p>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">Grid </span><span style="color: red;">x</span><span style="color: blue;">:</span><span style="color: red;">Name</span><span style="color: blue;">="LayoutRoot" </span><span style="color: red;">AllowDrop</span><span style="color: blue;">="True" </span><span style="color: red;">helper</span><span style="color: blue;">:</span><span style="color: red;">DropHelper.DropCommand</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">DropCommand</span><span style="color: blue;">}"</span></pre>
<pre class="code"> <span style="color: blue;">&lt;</span><span style="color: #a31515;">ListBox </span><span style="color: red;">ItemsSource</span><span style="color: blue;">="{</span><span style="color: #a31515;">Binding </span><span style="color: red;">ImagesCollection</span><span style="color: blue;">}"
</span></pre>
<p>Et voilà le tour est joué.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/08/glissez-des-fichiers-dans-votre-application-silverlight-depuis-lexplorateur-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Techdays 2010 &#8211; D&#233;veloppement d&#8217;une application m&#233;tier en WPF (retour d&#8217;exp&#233;rience)</title>
		<link>http://blog.experida.fr/2010/05/02/techdays-2010-dveloppement-dune-application-mtier-en-wpf-retour-dexprience/</link>
		<comments>http://blog.experida.fr/2010/05/02/techdays-2010-dveloppement-dune-application-mtier-en-wpf-retour-dexprience/#comments</comments>
		<pubDate>Sun, 02 May 2010 19:50:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Techdays]]></category>
		<category><![CDATA[Business Application]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/05/02/techdays-2010-dveloppement-dune-application-mtier-en-wpf-retour-dexprience/</guid>
		<description><![CDATA[Lors de la 4ème édition des Microsoft Techdays, j’ai eu la chance de co-présenter avec Damien Thouvenin gérant de CLT-Services, un retour d’expérience sur une application métier en WPF. Je vous laisse découvrir la vidéo et le document PowerPoint depuis le site des Microsoft Techdays:&#160; http://www.microsoft.com/france/vision/mstechdays10/Webcast.aspx?EID=aa76ca14-b41d-4b25-8caf-c8fc7788154e]]></description>
			<content:encoded><![CDATA[<p>Lors de la 4ème édition des Microsoft Techdays, j’ai eu la chance de co-présenter avec <a href="http://www.viadeo.com/fr/profile/damien.thouvenin" target="_blank">Damien Thouvenin</a> gérant de CLT-Services, un retour d’expérience sur une application métier en WPF.</p>
<p>Je vous laisse découvrir la vidéo et le document PowerPoint depuis le site des Microsoft Techdays:&#160; <a title="http://www.microsoft.com/france/vision/mstechdays10/Webcast.aspx?EID=aa76ca14-b41d-4b25-8caf-c8fc7788154e" href="http://www.microsoft.com/france/vision/mstechdays10/Webcast.aspx?EID=aa76ca14-b41d-4b25-8caf-c8fc7788154e">http://www.microsoft.com/france/vision/mstechdays10/Webcast.aspx?EID=aa76ca14-b41d-4b25-8caf-c8fc7788154e</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/05/02/techdays-2010-dveloppement-dune-application-mtier-en-wpf-retour-dexprience/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4 &#8211; StringFormat Binding Extension</title>
		<link>http://blog.experida.fr/2010/04/20/silverlight-4-stringformat-binding-extension/</link>
		<comments>http://blog.experida.fr/2010/04/20/silverlight-4-stringformat-binding-extension/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 19:56:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[Binding]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2010/04/20/silverlight-4-stringformat-binding-extension/</guid>
		<description><![CDATA[  Silverlight 4 vient tout juste de sortir en version finale et parmi les nouveautés, on peut remarquer l’apparition d’une extension de Binding nommée StringFormat. Comme vous l’imaginez, grâce à cette extension nous allons pouvoir décider du format d’affichage sans passer pas un nième converter. Prenons un exemple simple en partant du principe, que nous [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>Silverlight 4 vient tout juste de sortir en version finale et parmi les nouveautés, on peut remarquer l’apparition d’une extension de Binding nommée StringFormat.</p>
<p>Comme vous l’imaginez, grâce à cette extension nous allons pouvoir décider du format d’affichage sans passer pas un nième converter.</p>
<p><span id="more-49"></span></p>
<p>Prenons un exemple simple en partant du principe, que nous avons un objet contenant une date, bindé au DataContext d’un UserControl.</p>
<pre><code>
public class Blog {
  public string Name { get; set; }
  public DateTime CreationDate { get; set; }
} 

public partial class MainPage : UserControl
{
  public MainPage() {
    InitializeComponent();
    this.DataContext = new Blog { Name="MonBlog", CreationDate = DateTime.Now };
  }
}
</code></pre>
<p><strong> </strong></p>
<p>Avec Silverlight 3, vous deviez d’abord créer un Converter à l’aide de l’interface IValueConverter:</p>
<pre><code>
public class ShortDateConverter : IValueConverter
{
   public object Convert(object value, Type targetType, </code></pre>
<pre><code>      object parameter, System.Globalization.CultureInfo culture)
   {
       DateTime date;

       if (DateTime.TryParse(value.ToString(), out date))
          return date.ToShortDateString();

       return null;
   }
</code></pre>
<p> </p>
<p>Puis référencer ce converter dans les resources de votre UserControl, pour l’utiliser avec le Binding sur votre propriété.</p>
<pre><code>
&lt;UserControl.Resources&gt;
   &lt;local:ShortDateConverter x:Key="DateConverter" /&gt;
&lt;/UserControl.Resources&gt;
&lt;Grid x:Name="LayoutRoot" Background="White"&gt;
  &lt;TextBlock Text="{Binding CreationDate, </code></pre>
<pre><code>       Converter={StaticResource DateConverter}}"/&gt;
&lt;/Grid&gt;
</code></pre>
<p>Comme indiqué par le converter, le résultat qui s&#8217;affiche est bien un ShortDate, ici au format dd/MM/yyyy.</p>
<p>Pour arriver au même résultat avec Silverlight 4, nous allons tout simplement spécifier ce format à l&#8217;aide du mot clé StringFormat que l&#8217;on ajoute à la suite de notre élément Binding comme ceci.</p>
<pre><code>
&lt;UserControl.Resources&gt;
  &lt;local:ShortDateConverter x:Key="DateConverter" /&gt;
&lt;/UserControl.Resources&gt;
&lt;Grid x:Name="LayoutRoot" Background="White"&gt; </code></pre>
<pre><code>    &lt;TextBlock Text="{Binding CreationDate,StringFormat='dd/MM/yyyy'}"/&gt;</code><code>
&lt;/Grid&gt;
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2010/04/20/silverlight-4-stringformat-binding-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Construire une expression lambda</title>
		<link>http://blog.experida.fr/2009/11/22/64/</link>
		<comments>http://blog.experida.fr/2009/11/22/64/#comments</comments>
		<pubDate>Sun, 22 Nov 2009 08:17:44 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Linq]]></category>
		<category><![CDATA[Lambda Expression]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/?p=64</guid>
		<description><![CDATA[Les informations suivantes sont à prendre en compte avec les RIA Services CTP July, je n&#8217;ai pas testé avec la dernière version disponible de ces derniers jours. J&#8217;ai une application cliente en silverlight  qui utilise les RIA Services pour la validation, la récupération, l&#8217;insertion et la suppression des données. Lors de la compilation, un DomainContext est [...]]]></description>
			<content:encoded><![CDATA[<p>Les informations suivantes sont à prendre en compte avec les RIA Services CTP July, je n&#8217;ai pas testé avec la dernière version disponible de ces derniers jours.</p>
<p>J&#8217;ai une application cliente en silverlight  qui utilise les RIA Services pour la validation, la récupération, l&#8217;insertion<br />
et la suppression des données.</p>
<p><span id="more-64"></span></p>
<p>Lors de la compilation, un DomainContext est créé côté client avec les méthodes créées dans le DomainService sur le Serveur. Pour communiquer avec le serveur , le DomainContext utiliser un HttpHandler  &#8221; DataService.axd &#8221; qui va se charger de rediriger les appels  à la class &#8221; DataServiceFactory&#8221;, comme configuré dans le web.config:</p>
<p>&lt;add path=&#8221;DataService.axd&#8221; verb=&#8221;GET,POST&#8221; type=&#8221;System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35&#8243; validate=&#8221;false&#8221;/&gt;</p>
<p>Côté client, il nous reste juste à appeler la méthode asynchrone Load du DomainContext, en lui indiquant les données à charger, ici les types de logement:</p>
<p>context.Load(context.GetTypesLogementQuery().Where(filterClause), base.LoadCompleted, operationCallBack);</p>
<p>GetTypesLogementQuery retourne un EntityQuery&lt;TEntity&gt;. Cette classe représente une requête linq dans une collection d&#8217;entités, ie where TEntity : System.Windows.Ria.Data.Entity, qui est la classe de base pour chaque Entité côté client. Notre méthode GetTypesLogementQuery retourne donc un EntityQuery&lt;T_Types_Logement&gt;.</p>
<p>Maintenant si on soutaite filtrer les résultats, on va naturellement appeler la méthode Where qui est une méthode<br />
d&#8217;extension ( mot clé this)  sur IEnumerable&lt;T&gt;.</p>
<p>Avec les RIAServices, la méthode where prend en paramètre un object de type Expression&lt;Func&lt;TSource,Boolean&gt;&gt; réprésentant une expression (structure de données, permettant notamment<br />
de travailler sur les paramètres ou le corps d&#8217;une expression lambda) avec un Delegate prenant un TSource et retournant un boolean. Pour plus d&#8217;infos je vous renvoie vers un billet du blog CLT:<br />
<a href="https://mail.clt-services.com/owa/redir.aspx?C=6c54d2d535cb4b17821bb2a47131c6ff&amp;URL=http%3a%2f%2fclt-services.com%2fblog%2fpost%2fINotifyPropertyChanged-avec-Expression-Lambda.aspx" target="_blank">http://clt-services.com/blog/post/INotifyPropertyChanged-avec-Expression-Lambda.aspx</a></p>
<p>Cette petite intro pour en venir au problème suivant:<br />
Dans mon appli silverlight je souhaite mettre en place un système de filtres. Par exemple, afficher tous les logements<br />
de type appartement et maison</p>
<p>Une fois les filtres sélectionnés, je connais les Ids correspondant à appartement  et maison. Ils sont stockés dans une list&lt;int&gt; se trouvant dans mon<br />
viewModel. J&#8217;ai également mon controller avec cette méthode:</p>
<p> public void GetAll(Action&lt;IEnumerable&lt;T_Type_Logement&gt;&gt; operationCallBack, Expression&lt;Func&lt;T_Type_Logement,bool&gt;&gt; filterClause)<br />
{<br />
      context.Load(context.GetTypesLogementQuery().Where(filterClause), base.LoadCompleted, operationCallBack);<br />
}</p>
<p>Je pensais donc pouvoir  appeler cette méthode comme ceci :<br />
   GetAll(callback, t =&gt; MaList.Contains(t.T_Type_Logement_Id)<br />
l&#8217;équivalent d&#8217;une clause in en sql. Seulement problème j&#8217;ai le message d&#8217;erreur suivant :<br />
    Value of type &#8216;System.Collections.Generic.List`1[System.Int32]&#8216; cannot be serialized as part of the query. &#8216;System.Collections.Generic.List`1[System.Int32]&#8216; is not a supported Type.</p>
<p>Comment faire pour contourner ce problème.</p>
<p> J&#8217;ai donc décidé de créer de manière dynamique l&#8217;expression lambda à passer à notre controller, via des méthodes d&#8217;extensions sur des<br />
Expression&lt;Func&lt;TElement,TValue&gt;&gt;, ce qui nous donne le code suivant:</p>
<p>    public static class QueryBuilderHelper<br />
    {<br />
      <br />
        ///Cette méthode permet de créer le root pour notre expression<br />
        /// Where est un bloc conditionnel et je renvoie par défaut True, ce qui explique le bool de notre Delegate Func<br />
        public static Expression&lt;Func&lt;T, bool&gt;&gt; Create&lt;T&gt;() { return e =&gt; true; }<br />
      <br />
        ///Cette méthode est une extension sur Expression&lt;Func&lt;T, bool&gt;&gt;, ici le paramètre source, qui renvoie une expression du même type,<br />
        /// ce qui implique qu&#8217;on peut l&#8217;appeler en chaine.<br />
        /// selector, représente le champs sur lequel on veut filter, par exemple t.T_Type_Logement_Id<br />
        /// Keys, représente la collection des ids (Maison et Appartement)<br />
        public static Expression&lt;Func&lt;T, bool&gt;&gt; And&lt;T,TValue&gt;(this Expression&lt;Func&lt;T, bool&gt;&gt; source,<br />
                                                       Expression&lt;Func&lt;T, TValue&gt;&gt; selector,<br />
                                                       IEnumerable&lt;TValue&gt; keys)<br />
        {<br />
            //Via le Select, on projette chaque élément de la collection dans une nouvelle Expression<br />
            // représentant une égalité avec le champs indiqué dans selector: ex:  T_Type_Logement_Id = 1, puis on la met dans notre collection equals<br />
            IEnumerable&lt;Expression&gt; equals = keys.Select(value =&gt; (Expression)Expression.Equal(selector.Body, Expression.Constant(value, typeof(TValue))));<br />
            //Ensuite on applique la binary expression OrElse &#8221; || &#8221; entre chaque élément de notre collection Equals<br />
            Expression body = equals.Aggregate&lt;Expression&gt;((accumulate, equal) =&gt; Expression.OrElse(accumulate, equal));<br />
          <br />
            //Enfin, on construit notre nouvelle expression lambda, dans laquelle on utilise AndAlso  &#8220;&amp;&amp;&#8221; pour l&#8217;associer avec l&#8217;expression source<br />
            return Expression.Lambda&lt;Func&lt;T, bool&gt;&gt;(<br />
                Expression.AndAlso(source.Body, body), source.Parameters);<br />
        }<br />
    }</p>
<p>Maintenant quand on appelle la méthode GetAll de notre controller on a le code suivant:<br />
var wherePredicate = QueryBuilderHelper.Create&lt;T_Type_Logement&gt;().And(t =&gt; t.Type_Logement_Id, typesLogementKeys)<br />
typeLogementModelController.GetAll(callback,wherePredicate);</p>
<p>Voilà, on peut pousser le principe plus loin, en implémentant d&#8217;autres clauses</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2009/11/22/64/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Configuration ConnectionString pour fichier dbml</title>
		<link>http://blog.experida.fr/2009/11/11/configuration-connectionstring-pour-fichier-dbml/</link>
		<comments>http://blog.experida.fr/2009/11/11/configuration-connectionstring-pour-fichier-dbml/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 08:08:51 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[DAL]]></category>
		<category><![CDATA[connectionString]]></category>
		<category><![CDATA[dbml]]></category>
		<category><![CDATA[LinqToSql]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/?p=61</guid>
		<description><![CDATA[Lors de la création d&#8217;un fichier dbml sous Visual Studio, le code behind est automatiquement généré en fonction des tables qu&#8217;on ajoute graphiquement. Le premier constructeur appelle la class de base et lui passe la ConnectionString nécessaire pour la connection à la base de données. Cependant il ne faut pas coder en dur la ConnectionString dans [...]]]></description>
			<content:encoded><![CDATA[<p>Lors de la création d&#8217;un fichier dbml sous Visual Studio, le code behind est automatiquement généré en fonction des tables qu&#8217;on ajoute graphiquement.</p>
<p>Le premier constructeur appelle la class de base et lui passe la ConnectionString nécessaire pour la connection à la base de données. Cependant il ne faut pas coder en dur la ConnectionString dans ce code, car il sera automatiquement regénéré à chaque fois qu&#8217;une modification sera faite au niveau graphique du fichier dbml.</p>
<p><span id="more-61"></span></p>
<p><span style="text-decoration: underline;">Comment y remédier ?</span></p>
<p>Simplement en externalisant cette configuration. La chaîne de connection doit-être stockée dans un fichier de configuration. Si vous développez une application web, vous pouvez par exemple la mettre dans le web.config. En regardant à nouveau le fichier dbml, on voit qu&#8217;il s&#8217;agit d&#8217;une class partial, on peut donc créer notre propre class partial qui porte le même nom que la class d&#8217;origine, puis y ajouter le premier constructeur du DataContext généré automatiquement, en passant en paramètre à la class de base la ConnectionString à l&#8217;aide du ConfigurationManager. On peut créer facilement cette class en faisant clique droit sur le fichier dbml, puis ViewCode</p>
<p> System.Configuration.ConfigurationManager.ConnectionString["MaConnectionStringName"].ConnectionString</p>
<p> Voilà, la configuration est faite, si la bdd change, on aura juste à modificer le .config, mais pas la class du fichier dbml</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2009/11/11/configuration-connectionstring-pour-fichier-dbml/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight : trouver un &#233;l&#233;ment dans un ListBoxItem</title>
		<link>http://blog.experida.fr/2009/10/11/silverlight-trouver-un-lment-dans-un-listboxitem/</link>
		<comments>http://blog.experida.fr/2009/10/11/silverlight-trouver-un-lment-dans-un-listboxitem/#comments</comments>
		<pubDate>Sun, 11 Oct 2009 20:02:00 +0000</pubDate>
		<dc:creator>Alexandre Arnaudet</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[ListBoxItem]]></category>
		<category><![CDATA[VisualTreeHelper]]></category>

		<guid isPermaLink="false">http://blog.experida.fr/2009/10/11/silverlight-trouver-un-lment-dans-un-listboxitem/</guid>
		<description><![CDATA[En Silverlight comme en WPF, il existe un contrôle nommé ListBox auquel on peut Binder un IEnumerable&#60;T&#62; ce qui nous donne une liste populée avec un ensemble de ListBoxItem. Mon souhait était de créer un Menu composé d’HyperLinkButton afin d’utiliser notamment la propriété TargetName très utile en Silverlight 3 pour la navigation, et de lancer [...]]]></description>
			<content:encoded><![CDATA[<p>En Silverlight comme en WPF, il existe un contrôle nommé ListBox auquel on peut Binder un IEnumerable&lt;T&gt; ce qui nous donne une liste populée avec un ensemble de ListBoxItem.</p>
<p>Mon souhait était de créer un Menu composé d’HyperLinkButton afin d’utiliser notamment la propriété TargetName très utile en Silverlight 3 pour la navigation, et de lancer une animation automatiquement  sur le HyperLinkButton avec le VisualStateManager quand l’url courante  correspond au NavigateUri.</p>
<p><span id="more-52"></span></p>
<p>J’ai donc décidé de faire une  classe MenuItem avec trois propriétés ( NavigateUri, Content et TargetName), qui  au chargement de l’application sera utilisée pour créer une liste de MenuItem Bindée à mon contrôle Menu</p>
<p><span style="text-decoration: underline;"><strong>Au niveau Xaml nous avons le code suivant:</strong></span></p>
<p>&lt;ListBox ItemsSource=”{Binding MaSource}”&gt;</p>
<blockquote><p>&lt;ListBox.ItemTemplate&gt;</p>
<p>     &lt;DataTemplate&gt;</p>
<p>      &lt;HyperLinkButton TargetName=”{Binding TargetName}”  NavigateUri=”{Binding NavigateUri}”  Content=”{Binding Content}” /&gt;</p>
<p>     &lt;/DataTemplate&gt;</p>
<p>&lt;/ListBox.ItemTemplate&gt;</p></blockquote>
<p>&lt;/ListBox&gt;</p>
<p>Ensuite via un module interne à l’application mon contrôle menu connait à tout moment l’url courante. Cette Url est donnée via une DependencyProperty contenant une PropertyMetadata avec  un PropertyChangedCallBack. A chaque fois que l’url change le CallBack est appelé et je peux maintenant lancer l’animation.</p>
<p>Il nous reste plus qu’à trouver le bon HyperlinkButton dans la Listbox. Là est l’intérêt de ce billet. Comment faire ?</p>
<p>Si vous parcourez la propriété Items de votre List elle contiendra une collection de MenuItem c’est à dire  la liste bindée au début. Seulement ce que nous voulons c’est le HyperLinkButton et non le MenuItem, car la méthode GoToState du VisualStateManager prend en paramètre le contrôle sur lequel lancer l’animation, le nom du VisualState et un boolean pour indiquer si il y  a une transition.</p>
<p>Même si nous avons ajouté notre propre DataTemplate, la liste contient toujours des ListBoxItem que nous pouvons récupérer de la manière suivante:</p>
<p>foreach (MenuItem itm in MaListBox.Items)<br />
                {<br />
                    DependencyObject obj = MaListBox.ItemContainerGenerator.ContainerFromItem(itm);</p>
<p>}</p>
<p>Regardez le dependencyObject, nous avons bien un ListBoxItem. Comme vous devez vous en douter le ListBoxItem contient notre HyperLinkButton du départ. Pour l’extraire vous devrez faire appel à cette méthode Helper VisualTreeHelper présente dans System.Windows.Media ce qui au final nous donne ce code:</p>
<p><span style="text-decoration: underline;"><strong>Contenu du CallBack:</strong></span></p>
<p>NavigationMenu nav = d as NavigationMenu;<br />
            if (nav != null )<br />
            {<br />
                foreach (MenuItem itm in nav.menuListBox.Items)<br />
                {<br />
                    DependencyObject obj = nav.menuListBox.ItemContainerGenerator.ContainerFromItem(itm);<br />
                    HyperlinkButton btn = FindVisualChild&lt;HyperlinkButton&gt;(obj);</p>
<p>                    if (btn != null)<br />
                    {<br />
                        if (btn.NavigateUri.ToString() == e.NewValue.ToString())<br />
                            VisualStateManager.GoToState(btn, NavigationMenu.ActiveLinkState, true);<br />
                        else<br />
                            VisualStateManager.GoToState(btn, NavigationMenu.InactiveLinkState, true);<br />
                    }<br />
                }<br />
            }</p>
<p><strong><span style="text-decoration: underline;">Méthode appelée dans le CallBack et contenant VisualTreeHelper:</span></strong></p>
<p>public static childItem FindVisualChild&lt;childItem&gt;(DependencyObject obj)    where childItem : DependencyObject{<br />
           for (int i = 0; i &lt; VisualTreeHelper.GetChildrenCount(obj); i++)  <br />
           {     <br />
               DependencyObject child = VisualTreeHelper.GetChild(obj, i);<br />
               if (child is childItem)      <br />
                   return (childItem)child;  <br />
               else     <br />
               {        <br />
                   childItem childOfChild = FindVisualChild&lt;childItem&gt;(child);<br />
                   if (childOfChild != null)    <br />
                       return childOfChild;     <br />
               }<br />
           } <br />
           return null;<br />
       }</p>
<p>Voilà, nous arrivons au bout de ce petit billet, en espérant que ca puisse vous servir. Bon  coding <img src='http://blog.experida.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.experida.fr/2009/10/11/silverlight-trouver-un-lment-dans-un-listboxitem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

