Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Xamarin.Forms : Une amélioration décisive du Visual State Manager

Le VSM vous connaissez forcément (sinon c’est rageant !) puisque j’en ai fait un cycle de 3 vidéos … Mais depuis il y a eu une amélioration importante. Laquelle ? Suivez le guide !

Le Visual State Manager

Je ne vais pas ici refaire les trois vidéos ni même tout ce que j’ai pu écrire au sujet de cet outil XAML de la plus haute importance du temps de Silverlight, mais en deux mots il s’agit d’une construction XAML permettant de fixer des états (ayant un nom) ainsi que les changements visuels de ces états. L’application peut ensuite forcer le passage d’un état à l’autre, le visuel se mettant à jour tout seul.

Le VSM de Silverlight était plus évolué, mais celui des Xamarin.Forms s’améliore avec le temps…

Pour commencer je vous conseille vivement de regarder ces trois vidéos sur ce qu’est le VSM et comment l’utiliser :

Grâce à ces vidéos vous comprendrez mieux le billet qui va suivre, alors n’hésitez pas à faire une pause dans votre lecture pour aller les regarder.

La nouveauté

Le Visual State Manager (VSM) existe depuis Xamarin.Forms 3.0, mais l’équipe de développement a indiqué clairement que le travail continuait et que d’autres améliorations étaient attendues. L'une des choses qu’ils voulaient vraiment ajouter était la possibilité de modifier une propriété sur n'importe quel élément enfant dans la portée. Jusqu'à XF 3.0 vous ne pouviez définir que les valeurs des propriétés de l'élément auquel vous avez appliqué le VSM. Depuis Xamarin.Forms 4.5 la possibilité en question a été ajoutée. Elle ajoute beaucoup de flexibilité au VSM.

Le “problème” qui est résolu

Si on s’en tient aux possibilité de la première version du VSM vous comprenez donc qu’on définit un VSM à l’intérieur d’un objet visuel précis et que les propriétés qui sont touchées dans les différents états ne peuvent concerner que l’objet en cours.

Si nous créons un étant custom, par exemple l’état “Invalid”, et que nous voulons qu’il se répercute sur plusieurs objets visuels à la fois il faudra définir autant de fois le même code assez verbeux sur chaque contrôle, et prévoir le pilotage de l’état pour chacun d’eux en s’assurant d’être bien synchro !

C’est lourd, très lourd, tellement lourd que personnellement j’ai attendu la nouvelle fonction pour me servir à nouveau du VSM que j’adorais sous Silverlight. On n’y est pas encore tout à fait mais on s’en rapproche assez pour s’en servir dans tous les projets !

Alors revenons à notre code première version, à notre état “Invalid” que nous voulons voir supporter par plusieurs contrôles visuels à la fois. Oublions le pilotage de ces états, fixons nous juste sur le code XAML qui les définit et imaginons un code comme le suivant :

<StackLayout x:Name="MyStackLayout" HorizontalOptions="Center" VerticalOptions="CenterAndExpand">
         <VisualStateManager.VisualStateGroups>
             <VisualStateGroup x:Name="ColorStates">
                 <VisualState x:Name="Normal" />
                 <VisualState x:Name="Invalid">
                     <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Azure"/>
                     </VisualState.Setters>
                 </VisualState>
             </VisualStateGroup>
         </VisualStateManager.VisualStateGroups>

        <Label x:Name="WelcomeLabel" Text="Welcome to Xamarin.Forms!" HorizontalTextAlignment="Start" HorizontalOptions="Start">
             <VisualStateManager.VisualStateGroups>
                 <VisualStateGroup x:Name="ColorStates">
                     <VisualState x:Name="Normal" />
                     <VisualState x:Name="Invalid">
                         <VisualState.Setters>
                             <Setter Property="TextColor" Value="Red"/>
                         </VisualState.Setters>
                     </VisualState>
                 </VisualStateGroup>
             </VisualStateManager.VisualStateGroups>
         </Label>

        <Label x:Name="CurrentState"></Label>

        <Button x:Name="ToggleValidButton" Text="Toggle State" Clicked="ToggleValid_OnClicked">
             <VisualStateManager.VisualStateGroups>
                 <VisualStateGroup x:Name="ColorStates">
                     <VisualState x:Name="Normal" />
                     <VisualState x:Name="Invalid">
                         <VisualState.Setters>
                             <Setter Property="TextColor" Value="Red"/>
                         </VisualState.Setters>
                     </VisualState>
                 </VisualStateGroup>
             </VisualStateManager.VisualStateGroups>
         </Button>
     </StackLayout>


Rien de complexe, un StackLayout, un label et un bouton. Toutefois comme vous le remarquez pour gérer notre nouvel état “Invalid” qui doit avoir un effet sur les trois éléments à la fois nous sommes obligés de répéter le même code XAML de VSM pour chaque contrôle concerné. Ce n’est pas optimal c’est le moins qu’on puisse dire…

Mais heureusement cela n’était que temporaire ! Car désormais…

La nouveauté qui change tout

On y vient… Ce n’est pas grand-chose, il s’agit de l’option “TargetName” supportée dans les setters. Un peut rien du tout.

Mais qui change tout !

Tout le code exemple ci-dessous peut désormais s’écrire comme suit :

<StackLayout x:Name="MyStackLayout" HorizontalOptions="Center" VerticalOptions="CenterAndExpand">
         <VisualStateManager.VisualStateGroups>
             <VisualStateGroup x:Name="ColorStates">
                 <VisualState x:Name="Normal" />
                 <VisualState x:Name="Invalid">
                     <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Azure"/>

                        <!-- Added the two lines below -->
                         <Setter TargetName="WelcomeLabel" Property="Label.TextColor" Value="Red"/>
                         <Setter TargetName="ToggleValidButton" Property="Button.TextColor" Value="Red"/>
                         <!-- Look here! Added the two lines above -->

                    </VisualState.Setters>
                 </VisualState>
             </VisualStateGroup>
         </VisualStateManager.VisualStateGroups>

        <Label x:Name="WelcomeLabel" Text="Welcome to Xamarin.Forms!" HorizontalTextAlignment="Start" HorizontalOptions="Start" />

        <Label x:Name="CurrentState"></Label>

        <Button x:Name="ToggleValidButton" Text="Toggle State" Clicked="ToggleValid_OnClicked"></Button>
     </StackLayout>

Plus aucune répétition de blocs VSM inutiles. Dans le changement d’état “Invalid” du contrôle de plus haut niveau (par logique, donc ici le stackLajout mais ce n’est pas une obligation) nous ajoutons juste les changements concernant le bouton et le label, c’est tout.

On gagne bien entendu en taille de code, en maintenabilité, etc, mais aussi en matière de pilotage des états, partie que je nous vous ai pas montré ici. Quelque part dans le code C# il faudra en effet faire basculer l’état des contrôles. S’il y a trois contrôles à modifier et si on en ajoute un quatrième cela fait pas mal de maintenance et d’erreurs possibles. Ici l’état invalid concerne un groupe de contrôle dans un StackLayout et le code ne fera que changer l’état de ce dernier. Tout le reste suivra. C’est essentiel pour une programmation efficace.

Conclusion

Un simple petit mot, TargetName, et c’est toute la puissance du VSM qui explose, des tonnes de code XAML qui disparaissent, une logique de contrôle qui se simplifie… Parfois le bonheur ne tient à pas grand-chose…

Il tient par exemple au fait de rester au courant en lisant Dot.Blog (abonnez-vous à la lettre d’info pour être prévenu des nouveaux articles) et abonnez-vous à ma chaîne Youtube pour ne pas loupez les vidéos Xamarin.Forms, celles sur les IoT ou le complément du blog Dot.Vlog !

Et puis surtout…

Stay Tuned !

blog comments powered by Disqus