If gentil Then cadeau Else baton

HoHoHo ! C’est bientôt le moment des cadeaux de noël, petit ami développeur !

pere-noel-geek

As-tu été un bon petit codeur ? As-tu bien implémenté ? Bien MVVMé ? Bien publié ?
La ! la ! c’est bon !
Regarde dans la cheminée de ton chalet secondaire ce que le Père noël XAML t’apporte un peu en avance !

92411529

Du XAML Conditionnel !

Ah ! Enfin du If-Then-Else dans nos pages XAML chéries !
Attention on ne parle pas ici de directive de préprocesseur (comme #if #else #endif en C#) mais bien de balise conditionnelle (if{}else if{} en c#).

Avant de passer aux exemples commençons par installer la librairie dans notre projet.

Installation

Rien de plus facile puisque c’est un paquet NuGet !
Attention il ne fonctionne que pour les applications WinRT (Universal).

Un bouton droit sur notre projet WinRT, puis « Manage NuGet Packages »

NugetManage

Cherchez le paquet « Conditional XAML » puis installer. Le tour est joué !

NugetConditionalXaml

Vous ne comprenez rien à Nuget (Huh!), Je vous mets la librairie ici, bien au chaud.
Attention tout de même car seul NuGet sera mis à jour par la suite !

Namespace

Rajoutez maintenant un namespace dans votre page xaml qui pointe vers la librairie comme suit :

<Page
    ...
    xmlns:sb="using:SamuelBlanchard.Controls.Statements"
    ...
>

Maintenant On peut commencer à utiliser nos nouvelles balises !

Avec des si

Pour débuter, un premier exemple tout simple.
Ajoutez pour la démo un ToggleSwitch à notre page (Une sorte checkbox dont l’attribut IsOn renvoie true ou false)

<StackPanel>
    <ToggleSwitch x:Name="Checkbox" IsOn="True"></ToggleSwitch>
</StackPanel>

Puis à la suite du ToggleSwitch la balise Statement. Celui ci sera chargé d’héberger la balise if et d’afficher éventuellement son résultat.

<sb:Statement>
...
</sb:Statement>

On va maintenant ajouter la balise if.

<sb:Statement>
   <sb:If Then="Bonjour" Else="Au revoir">
   ...
   </sb:If>
</sb:Statement>

Comme vous le voyez les attributs Then et Else correspondent aux résultats du if.
Ici deux chaines de caractères « Bonjour » et au « Revoir ».
Mais il manque encore la condition.
On souhaiterait vérifier que le IsOn de la Checkbox est vrai.
On utilise donc une condition de test pour Boolean :

<sb:BooleanCondition Value1="{Binding ElementName=Checkbox, Path=IsOn}" Operator="Equal"Value2="True"/>

ou en simplifiant, la valeur d' »Operator » étant « Equal » par défaut :

<sb:BooleanCondition Value1="{Binding ElementName=Checkbox, Path=IsOn}" Value2="True"/>

La première valeur de cette condition (Value1) contient un Binding dont la source pointe vers la CheckBox via ElementName.
Le Path pointe vers la propriété « IsOn » de la CheckBox que l’on veut tester.

Finalement on obtient :

<sb:Statement>
   <sb:If Then="Bonjour" Else="Au revoir">
       <sb:BooleanCondition Value1="{Binding ElementName=Checkbox, Path=IsOn}" Operator="Equal"Value2="True"/>
   </sb:If>
</sb:Statement>

Lorsque l’on teste l’application, si la Checkbox est cochée le tag Statement affiche « Bonjour » dans le cas contraire « Au revoir ».

basic

Basic-Off

Autres conditions

J’ai implémenté quelques conditions de base pour que le if couvre la plupart des cas que l’on peut rencontrer dans une application.

BooleanCondition : gère le type bool.

DoubleCondition : gère le type double. Permet de comparer deux valeurs de type double avec les operateurs ==, !=, >, >=, <, <=

StringCondition : gère le type String. Permet de comparer deux valeurs de type string avec les actions suivantes : Equal, Different, Contains, StartsWith, EndsWith, RegEx. RegEx permet de tester une expression régulière ce qui est assez pratique dans des scénarios de comparaison complexe. Une propriété IsCaseSensitive permet d’effectuer la comparaison en prenant en compte ou non la casse de la chaine.

DateTimeCondition, DateTimeOffsetCondition, TimeSpanCondition : gère le temps et la durée. Très pratique pour tester des valeurs des contrôles tel que DatePicker ou TimePicker.

Comme on peut ajouter autant de condition que l’on souhaite dans un if voila un exemple d’utilisation de plusieurs conditions à la suite :

<StackPanel>
    <ToggleSwitch x:Name="CheckboxConditions" IsOn="True"></ToggleSwitch>
    <Slider x:Name="SliderConditions" Value="50"></Slider>
    <TextBox x:Name="TextBoxName" Text="Samuel"></TextBox>
    <DatePicker x:Name="DatePickerConditions1"></DatePicker>
    <DatePicker x:Name="DatePickerConditions2"></DatePicker>

    <sb:Statement FontSize="30">
        <sb:If Then="Bonjour" Else="Au revoir">
            <sb:BooleanCondition Value1="{Binding ElementName=CheckboxConditions, Path=IsOn}" Operator="Equal" Value2="True"></sb:BooleanCondition>
            <sb:DoubleCondition Value1="{Binding ElementName=SliderConditions, Path=Value}" Operator="Greater" Value2="60.0"></sb:DoubleCondition>
            <sb:StringCondition Value1="{Binding ElementName=TextBoxName, Path=Text}" IsCaseSensitive="False" Operator="StartsWith" Value2="Sam"></sb:StringCondition>
            <sb:DateTimeOffsetCondition Value1="{Binding ElementName=DatePickerConditions1,Path=Date}" Operator="Greater" Value2="{Binding ElementName=DatePickerConditions2,Path=Date}"></sb:DateTimeOffsetCondition>
        </sb:If>
    </sb:Statement>
</StackPanel>

Bonus:

J’ai rajouté également deux comparaisons très pratiques (encore des cadeaux !).
Il s’agit de :

ScreenOrientationCondition : Permet de comparer l’orientation actuelle

IsDesignTimeCondition : Permet de déterminer si l’on est en mode design ou pas

<StackPanel>
    <sb:Statement FontSize="30">
        <sb:If Then="Landscape" Else="Portrait">
            <sb:ScreenOrientationCondition Orientation="IsLandscape"/>
        </sb:If>
    </sb:Statement>
    <sb:Statement FontSize="30">
        <sb:If Then="Design" Else="RunTime">
            <sb:IsDesignerModeCondition/>
        </sb:If>
    </sb:Statement>
</StackPanel>

J’écrirais un article prochainement sur la création de condition complémentaire mais en attendant si vous trouvez d’autres conditions n’hésitez pas à me laisser un commentaire.

Opérateur logique

Comme vous l’avez vu dan le dernier paragraphe il est possible d’ajouter autant de conditions dans la balise if que l’on désire.
Par défaut on effectue pour chaque résultat de condition un ET logique pour obtenir le resultat final. Mais Il est également possible d’utiliser d’autre opérateurs logiques :

Or : OU logique effectué entre tous les enfant de la balise

Not: Inverse le résultat global issu de tous les enfants de la balise. Il est aussi possible d’utiliser l’attribut « IsInverted » sur toutes les conditions et tous les If.

Xor : really ?

<StackPanel>
    <ToggleSwitch x:Name="CheckboxOp" IsOn="True"></ToggleSwitch>
    <Slider x:Name="SliderOp" Value="50"></Slider>
    <TextBox x:Name="TextBoxOp" Text="Samuel"></TextBox>
    <DatePicker x:Name="DatePickerOp1"></DatePicker>
    <DatePicker x:Name="DatePickerOp2"></DatePicker>

    <sb:Statement FontSize="30">
        <sb:If Then="Bonjour" Else="Au revoir">
            <sb:Or>
                <sb:Or.Conditions>
                    <sb:Not>
                        <sb:Not.Conditions>
                            <sb:BooleanCondition Value1="{Binding ElementName=CheckboxOp, Path=IsOn}" Operator="Equal" Value2="True"></sb:BooleanCondition>
                        </sb:Not.Conditions>
                    </sb:Not>
                    <sb:Xor>
                        <sb:Xor.Conditions>
                            <sb:DoubleCondition Value1="{Binding ElementName=SliderOp, Path=Value}" Operator="Greater" Value2="60.0"></sb:DoubleCondition>
                            <sb:StringCondition Value1="{Binding ElementName=TextBoxOp, Path=Text}" IsCaseSensitive="False" Operator="StartsWith" Value2="Sam"></sb:StringCondition>
                        </sb:Xor.Conditions>
                    </sb:Xor>
                </sb:Or.Conditions>
            </sb:Or>
            <sb:DateTimeOffsetCondition Value1="{Binding ElementName=DatePickerOp1,Path=Date}" Operator="Greater" Value2="{Binding 

ElementName=DatePickerOp2,Path=Date}"></sb:DateTimeOffsetCondition>
        </sb:If>
    </sb:Statement>
</StackPanel>

Ceux qui suivent encore s’apercevront que les enfants des balises Or,Not et Xor sont contenus dans une balise « Conditions » au lieu d’être directement placé à l’intérieur. C’est pour pallier à un bug qui empêche l’affichage de contenu direct après un certain niveau dans la hiérarchie: « Syntax Error found in XBF generation ». Si vous connaissez la solution à ce problème n’hésitez pas à me laisser un commentaire.

Then et Else

Les attributs Then et Else sont de type Objet.
Ils peuvent donc contenir autre chose que des chaînes de charactère.
Ils peuvent par exemple contenir du XAML, des StaticResources et même d’autre If !

<StackPanel>
    <ToggleSwitch x:Name="CheckboxThenElse" IsOn="True"></ToggleSwitch>
                    
    <sb:Statement FontSize="30">                                                
        <sb:If>
            <sb:ScreenOrientationCondition Orientation="IsPortrait"></sb:ScreenOrientationCondition>
                            
            <sb:If.Then>
                <Button Content="Bonjour"></Button>
            </sb:If.Then>
            <sb:If.Else>
                <sb:If Else="Rien du tout">
                    <sb:BooleanCondition Value1="{Binding ElementName=CheckboxThenElse, Path=IsOn}" Operator="Equal" Value2="True"></sb:BooleanCondition>
                    <sb:If.Then>
                        <DatePicker></DatePicker>
                    </sb:If.Then>
                </sb:If>
            </sb:If.Else>                            
        </sb:If>
    </sb:Statement>
</StackPanel>

Attribut Result

Il peut arriver que seul le résultat du If nous intéresse afin que ce résultat soit bindé sur un autre control.
L’affichage du statement doit donc être désactivé.
Pour ce faire, on affecte la propriété « ShowResult » du control Statement à false.
Il ne nous reste plus qu’à binder la propriété « Result » du If sur le controle.

<StackPanel>
    <ToggleSwitch x:Name="CheckboxResult" IsOn="True"></ToggleSwitch>

    <sb:Statement ShowResult="False">
        <sb:If x:Name="IfVisibility" Then="Visible" Else="Collapsed">
            <sb:BooleanCondition Value1="{Binding ElementName=CheckboxResult, Path=IsOn}" Value2="True"></sb:BooleanCondition>
        </sb:If>
    </sb:Statement>
                    
    <Button Content="Hello" Visibility="{Binding ElementName=IfVisibility, Path=Result}"></Button>
                    
</StackPanel>

Ce type de Binding est très utile pour gérer des formulaires, des affichages d’images bref de modifier n’importe quelle propriété d’un contrôle.

Conclusion

Hohoho ! Alors votre cadeau de joyeux X-MAL ? Il vous plaît ?
Le père noël voulait remercier également le lutin Benjamin Roux pour son aide sur les collections de DependencyObject :)

Le projet reprenant tous les exemples de cet article se trouve ici.

Merry XMAS les amis !

SantaSmoke

leave your comment