Faire un Slider XAML complet en 5 petites étapes
Si vous êtes à l'aise avec le XAML, passez directement à l'etape 4.
Le slider est un control XAML des plus basique. Il est très simple à mettre en place. Cependant, je lui reproche son manque de personnalisation. Si il est aisé de changer sa couleur de fond ou sa largeur, nous sommes vite limités. Naturellement, si nous souhaitons augmenter la hauteur de notre Slider, nous pensons à augmenter la valeur de l’attribut Height. Essayons.
Le premier Slider a la Height par défaut. Le second possède une Height à 200.
Décevant n'est-ce pas ? Nous avons agrandi la taille du control mais le slider en lui-même n'a pas bougé.
Habituellement pour toute personnalisation d'un Slider, il est de rigueur d'en éditer le template.
Je vais vous proposer une autre solution. Nous remarquons un léger problème. Si nous glissons le doigt le long du bas du control, nous prennons la main sur le slider sans vraiment le toucher. C'est grâce à cette feature que l'astuce que je vais vous présenter fonctionne.
N'hésitez pas à tester chaque snippet tout au long de l'article.
Dans un StackPanel, nous allons placer une Grid et un Slider. Nous nommons le StackPanel "ContainerSlider", la Grid "FakeSlider1" et le Slider "Slider1". Ensuite, bindons l'attribut Maximum à l'ActualWidth de ContainerSlider1 et bindons la Width de la Grid à la Value de Slider1
<StackPanel x:Name="ContainerSlider1"> <Grid x:Name="FakeSlider1" HorizontalAlignment="Left" Background="Orange" Height="24" Width="{Binding ElementName=Slider1, Path=Value }" /> <Slider x:Name="Slider1" Minimum="0" Maximum="{Binding ActualWidth, ElementName=ContainerSlider1}" Value="50" /> </StackPanel>
Dans notre code, remplaçons le StackPanel par une Grid. Ajoutons à ContainerSlider1 un Background BlueViolet. Ce qui nous intéresse ici, c'est la superposition propre à l'élément Grid. ContainerSlider1 prend la taille de Slider1. Slider1 qui est le dernier élément de ContainerSlider1 se trouve au premier plan.
<Grid x:Name="ContainerSlider1" Background="BlueViolet"> <Grid x:Name="FakeSlider1" Background="Orange" HorizontalAlignment="Left" Width="{Binding Value, ElementName=Slider1}"></Grid> <Slider x:Name="Slider1" Height="100" Minimum="0" Maximum="{Binding ActualWidth, ElementName=ContainerSlider1}" Value="50" /> </Grid>
A présent nous allons régler l'opacité de Slider1 à 0 et changer les couleurs de nos Grid. Je trouve qu'à ce stade nous avons déjà un rendu plutôt intéressant. Qu'en pensez-vous ?
<Grid x:Name="ContainerSlider1" Background="{StaticResource PhoneChromeBrush}"> <Grid x:Name="FakeSlider1" Background="{StaticResource PhoneAccentBrush}" HorizontalAlignment="Left" Width="{Binding Value, ElementName=Slider1}"></Grid> <Slider x:Name="Slider3" Opacity="0" Height="100" Minimum="0" Maximum="{Binding ActualWidth, ElementName=ContainerSlider1}" Value="50" /> </Grid>
Nous allons créer un curseur. Insérons une nouvelle Grid entre Slider1 et FakeSlider1. Nous nommons cette Grid "Cursor1". Sa largeur est de 20. Afin que notre curseur soit toujours à droite de FakeSlider, nous allons les placer dans un StackPanel horizontale. Pour centrer le curseur, il suffit de lui ajouter une marge négative à gauche équivalente à la moitié de sa largeur. Avec une largeur de 20, nous obtenons une marge de -10.
<Grid x:Name="ContainerSlider1" Background="{StaticResource PhoneChromeBrush}"> <StackPanel Orientation="Horizontal"> <Grid x:Name="FakeSlider1" Background="{StaticResource PhoneAccentBrush}" Width="{Binding Value, ElementName=Slider1}"></Grid> <Grid x:Name="Cursor1" Width="20" Margin="-10,0,0,0" Background="{StaticResource PhoneForegroundBrush}"/> </StackPanel> <Slider x:Name="Slider1" Opacity="0" Height="100" Minimum="0" Maximum="{Binding ActualWidth, ElementName=ContainerSlider1}" Value="50" /> </Grid>
Cette étape sert à rendre le comportement du curseur plus réaliste. En fonction de la localisation du curseur, nous modifierons la valeur de la marge.
private void Slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (Slider1 != null) Cursor1.Margin = SetCursorMargin(ContainerSlider1.ActualWidth, Cursor1.Width, e.NewValue); } private Thickness SetCursorMargin(double containerWidth, double thumbWidth, double sliderValue) { Thickness marginCursor = new Thickness(); double cursorWidthHalf = thumbWidth / 2; if (sliderValue < cursorWidthHalf) marginCursor.Left = -sliderValue; else if (sliderValue > containerWidth - cursorWidthHalf) marginCursor.Left = -(thumbWidth + sliderValue - containerWidth); else marginCursor.Left = -thumbWidth / 2; return marginCursor; }
J'ai fait en sorte de rendre le code ci-dessus le plus compréhensible possible, quitte à mettre de côté des questions de performance. Il n'en est pas sujet ici.
Ce slider n'est rien d'autre qu'un ensemble de Grid. On peut mettre absolument tout et n'importe quoi dedans. Vous pouvez parfaitement remplacer le curseur par une image, du texte, une vidéo, un calendrier, etc.
Il est possible de créer un slider facilement manipulable et modifiable avec deux Binding et un slider classique. Il suffit de rendre le slider invisible et de compter sur sa large zone tactile.
Retrouvez l'ensemble des sources de cet article sur mon GitHub