Ecrire du texte à 90° dynamiquement pour Windows Phone et Metro App Style !



Il arrive parfois que le design d’une application nécessite l’écriture d’un texte à 90°.
En XAML, le control TextBlock est chargé de la gestion du texte mais malheureusement aucune option d’orientation n’existe.
Nous allons donc l’implémenter, ensemble, au cours de cet article.

Nous aurions pu réaliser un behavior pour gérer cette problématique mais par souci de simplicité nous étudierons uniquement le XAML (et éventuellement le code) à générer pour produire l’effet.

L’objectif final étant d’obtenir ceci :


Un RenderTransform pour basculer


La première chose à effectuer pour écrire à 90° est évidemment de faire pivoter notre texte à 90°.

Pour se faire un simple CompositeTransform dans un RenderTransform devrait suffire avec une rotation de -90°(ou 270° au choix)

<TextBlock FontSize="80" Text="ANGLE90">
    <TextBlock.RenderTransform>
        <CompositeTransform Rotation="-90"></CompositeTransform>
    </TextBlock.RenderTransform>
</TextBlock>

Mais le texte sort désormais de l’écran et selon son positionnement dans le XAML soit il écrase d’autres éléments (le cas dans notre exemple) soit on ne le voit plus.
Pour s’en persuader jeter un coup d’oeil sur cette capture.

Pour être bien placer On devrait ajouter à la position Y du texte, sa propre taille.
On pourrait calculer la taille en pixel du texte à la main mais ce n’est pas très pratique (en cas de localisation du texte encore moins).

Le TextBlock connait sa taille à travers sa propriété ActualWidth.
Bindons cette propriété sur la propriété TranslateY du CompositeTransform.

** ATTENTION CETTE TECHNIQUE NE FONCTIONNE QUE SUR WP7 **
(voir le paragraphe Du dynamisme dans notre texte pour ne solution Metro App Style)

<TextBlock x:Name="TextBlockChoisissez" FontSize="80" Text="ANGLE90">
    <TextBlock.RenderTransform>
	<CompositeTransform Rotation="-90" TranslateY="{Binding Path=ActualWidth, ElementName=TextBlockChoisissez}"></CompositeTransform>
    </TextBlock.RenderTransform>
</TextBlock>

Tout rentre dans l’ordre !


Les layout


Alors que l’objectif semble atteint, un nouveau problème est pourtant bien toujours présent !
En effet, le layout du TextBlock ne prend pas en compte la rotation de notre texte et s’appuie toujours sur l’orientation du texte original.

Si j’entoure par exemple notre Texte d’un StackPanel à l’orientation vertical tout en incluant un carré bleu, celui-ci ne sera pas collé au texte en rotation mais repoussé de la taille du texte original.

<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">

        <TextBlock x:Name="TextBlockChoisissez" FontSize="80" Text="ANGLE90">
            <TextBlock.RenderTransform>
                <CompositeTransform Rotation="-90" TranslateY="{Binding Path=ActualWidth, ElementName=TextBlockChoisissez}"></CompositeTransform>
            </TextBlock.RenderTransform>
        </TextBlock>
                
    <Rectangle Width="100" Height="100" Fill="Blue"></Rectangle>                
</StackPanel>

Regardez cette capture pour le constater (le textblock en transparence n’existe pas et a été rajouté afin de mieux comprendre la problématique).

On doit donc faire sortir notre textBlock du Layout tout en donnant une taille à son conteneur identique à celle du TextBlock en rotation.
En entourant le TextBlock d’un Canvas dont la taille est bindée sur celle du TextBlock (mais inversé pour prendre en compte la rotation) on obtient l’effet voulu.

<Canvas VerticalAlignment="Bottom" Width="{Binding Path=ActualHeight, ElementName=TextBlockChoisissez}" Height="{Binding Path=ActualWidth, ElementName=TextBlockChoisissez}">
    <TextBlock x:Name="TextBlockChoisissez" FontSize="80" Text="ANGLE90">
    <TextBlock.RenderTransform>
        <CompositeTransform Rotation="-90" TranslateY="{Binding Path=ActualWidth, ElementName=TextBlockChoisissez}"></CompositeTransform>
    </TextBlock.RenderTransform>
    </TextBlock>
</Canvas>

Le canvas nous permet, de plus, de le positionner comme bon nous semble (Horizontal et vertical Alignment par exemple)


Inverser l’écriture


Pour obtenir un texte inversé comme dans l’image ci-dessous remplacer le CompositeTransform par celui-ci :

<CompositeTransform Rotation="90" TranslateX="{Binding Path=ActualHeight, ElementName=TextBlockChoisissez}"></CompositeTransform>


Du dynamisme dans notre texte


Notre affichage à 90° comporte encore quelques inconvénients plus ou moins gênant :

  • Il ne fonctionne pas dans une Metro App Style
  • Sur WP7, pendant un très court moment on peut voir apparaitre la position initiale du TextBlock (seul les transitions sont touchées).
  • Si le texte change, la taille du Canvas n’est pas mise à jour.



Le responsable de ces problèmes sont les propriété de l’ActualWidth et ActualHeight du TextBlock qui ne notifient pas leurs changements.
Il y a plusieurs façons de résoudre ce problème. Nous allons utiliser ici la plus simple.

On abonne le TextBlock à l’évènement LayoutUpdated pour affecter la taille du Canvas et les translation du CompositeTransform.

coté XAML:

<Canvas x:Name="Canvas" Background="Green" VerticalAlignment="Bottom" HorizontalAlignment="Right">

    <TextBlock x:Name="TextBlockChoisissez" FontSize="80" Text="{Binding Path=Text, ElementName=TextBoxChoisissez}" LayoutUpdated="TextBlockChoisissez_LayoutUpdated">
        <TextBlock.RenderTransform>
            <CompositeTransform x:Name="Composite" Rotation="-90" ></CompositeTransform>
            <!--<CompositeTransform x:Name="Composite" Rotation="-90" ScaleX="-1" ScaleY="-1"></CompositeTransform>-->
        </TextBlock.RenderTransform>
    </TextBlock>
</Canvas>

Coté C#:

private void TextBlockChoisissez_LayoutUpdated(object sender, EventArgs e)
{
    this.Canvas.Width = this.TextBlockChoisissez.ActualHeight;
    this.Canvas.Height = this.TextBlockChoisissez.ActualWidth;
    // en cas d'inversion de texte commenter TranslateY et décommenter TranslateX
    this.Composite.TranslateY = this.TextBlockChoisissez.ActualWidth;
    //this.Composite.TranslateX = this.TextBlockChoisissez.ActualHeight;
}

On a également bindé le texte du TextBlock à une TextBox afin de vérifier que le texte tapé met bien à jour la taille du Canvas.
En commentaire on trouvera tout ce qu’il faut pour l’inversion du texte.



Le résultat pour Windows Phone 7 :





Le résutat pour Matro Srtyle App :



Conclusion



On a vu ensemble comment réaliser pas à pas une rotation de text à 90° tout en abordant les différents problèmes qui pourraient intervenir.
Cette solution est applicable aussi bien à WP7 que Metro App Style et sans doute à WPF (non testé).
Comme indiquer dans l’introduction de cet article, il pourrait être intéressant de produire un behavior si les rotations sont utilisés fréquemment dans l’application.


Merci à Rudy Huyn pour se relecture attentive.



leave your comment