MediaQueries allégé pour Silverlight

Pendant la session très réussie de David Rousset, hier, au MsDays de Rennes, sur HTML5, je restais bluffé par une petite démo basée sur « Media Queries ».
Dans cette démo, on voyait l’interface graphique d’une application web changer complétement d’aspect pour s’adapter à la taille du naviguateur.
Lorsque le naviguateur avait une petite taille, l’interface affichait une information minimale, en revanche s’il disposait d’une taille plus respectable, de nouveaux elements venait la compléter et la réarranger.
Vous pouvez vous faire une idée de la chose en testant cet exemple : http://www.alistapart.com/d/responsive-web-design/ex/ex-site-FINAL.html avec un navigateur compatible CSS3 (IE9 en fait partie).

Pendant la démonstration, je me suis demandé si la chose était possible en Silverlight. La réponse est bien évidemment oui !
Il y a plusieurs façons d’aborder le problème : Behavior, Converter,… J’ai choisi l’approche qui me paraissait la plus simple à utiliser : Créer un controle spécifique. Je l’ai nommé (pompeusement) MediaQueries. Vous trouverez le résultat de mon travail sur cette vidéo :

L’appel du control s’effectue comme suit :

        <my:MediaQueries Background="Red">
            <my:MediaQueries.Items>
                <my:MediaQueriesItem MaxWidth="300">
                    <Grid Margin="10">

                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                        </Grid.RowDefinitions>

                        <Button Content="Small" Grid.Row="0"></Button>
                        <Button Content="Small" Grid.Row="1"></Button>
                    </Grid>
                </my:MediaQueriesItem>
                <my:MediaQueriesItem MinWidth="700">
                        <Button Content="Extra Big"></Button>
                </my:MediaQueriesItem>
                <my:MediaQueriesItem MinWidth="300">
                    <Grid Margin="10">

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>

                        <Button Content="Big" Grid.Column="0"></Button>
                        <Button Content="Big" Grid.Column="1"></Button>
                    </Grid>
                </my:MediaQueriesItem>
            </my:MediaQueries.Items>
        </my:MediaQueries>

Selon la taille du control et celle fixé dans les MédiaQueriesItem par les propriété MinWidth, MinHeight et MaxWidth et MaxWidth, un item sera choisi et affiché.

ATTENTION : Il n’y a pas de tri lors de la sélection du MédiaQueriesItem. Le premier qui correspond à la taille du control sera affiché. Voila pourquoi, si vous utilisez les propriétés MinWidth/MinHeight, il vaut mieux les trier du plus grand au plus petit et du plus petit au plus grand pour les propriétés MaxWidth/MaxHeight.

Pour les curieux, le control est composé d’un Templated Control héritant d’un ItemsControl ce qui lui permet d’avoir des enfants de type MediaQueriesItem.
Les changements de taille sont détectés par l’évenement SizeChanged.
On parcourt alors la liste des MediaQueriesItem pour trouver l’item le plus approprié et on le place dans une Dependency Property nommé SelectedItem.
Le control possède pour Template un simple Border ayant pour contenu le SelectedItem.

Ce control pourrait être adapté facilement à WPF.

Pour plus de détails je vous laisse consulter le code source.

EDIT : Je viens de mettre à jour la solution.

L’évenement SizeChanged n’est plus fixé sur le control mais sur l’objet RootVisual ce qui permet plus de souplesse (plusieurs controles MediaQueries peuvent être mise en place dans la même page).
Les propriétés Min… et Max… sont remplacées par des ScreenMin… et ScreenMax… afin que leurs fonctions soient bien distinguées.

        <my:MediaQueries Background="Red">
            <my:MediaQueries.Items>
                <my:MediaQueriesItem ScreenMaxWidth="300">
                    <Grid Margin="10">

                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                        </Grid.RowDefinitions>

                        <Button Content="Small" Grid.Row="0" Loaded="Button_Loaded"></Button>
                        <Button Content="Small" Grid.Row="1"></Button>
                    </Grid>
                </my:MediaQueriesItem>
                <my:MediaQueriesItem ScreenMinWidth="700">
                        <Button Content="Extra Big"></Button>
                </my:MediaQueriesItem>
                <my:MediaQueriesItem ScreenMinWidth="300">
                    <Grid Margin="10">

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>

                        <Button Content="Big" Grid.Column="0"></Button>
                        <Button Content="Big" Grid.Column="1"></Button>
                    </Grid>
                </my:MediaQueriesItem>
            </my:MediaQueries.Items>
        </my:MediaQueries>

Désormais, lorsqu’il n’y a aucun MediaQueriesItem qui correspondent à la taille, il n’affiche rien. On peut donc faire apparaitre/disparaitre simplement certaines parties de l’interface graphique.

La nouvelle source se trouve ici.