Dans cet article nous allons mettre en place pas à pas une application tactile multitouch avec le framework .NET 4.0 qui reproduira le comportement du scatterView bien connu de Microsoft Surface. Pour cela nous étudierons plus particulièrement les événements liés aux manipulations.
Présentation des différents éléments
Le framework .NET 4.0 apporte beaucoup de nouveautés afin de faciliter l'utilisation du MultiTouch dans vos applications WPF. En effet, tout les éléments dérivant de UIElement sont devenus sensibles aux événements tactiles et plus précisément aux "
manipulations tactiles". Les manipulations tactiles sont tout simplement les actions que vous allez produire sur vos objets avec un ou plusieurs doigts : rotations, translations, agrandisements/réductions.
Ces différents informations sont rendus disponibles en s'abonnant aux différents événements :
- ManipulationStarting : la manipulation va commencer : utile pour la configurer,
- ManipulationStarted : la manipulation est commencée,
- ManipulationDelta : la manipulation est en cours et évolue,
- ManipulationCompleted : la manipulation est terminée (tous les doigts sont partis )
Attention, pour que ces événement soient déclenchés, il faut mettre la propriété IsManipulationEnabled de l'élément à "True" !
L'événement le plus important est bien sûr
ManipulationDelta puisceque c'est celui-ci qui va nous indiquer quelle est l'évolution de la manipulation et nous indiquer via sa propriété
DeltaManipulation (oui c'est l'inverse du nom de l'événement :-) )
les gestes efffectués par l'utilisateur.
Un autre événement important est
ManipulationStarting puiscequ'il permet de configurer (
un peu) comment va se comporter la manipulation. Le plus important pour moi étant de configurer le
ManipulationContainer qui va indiquer l'élément qui servira de référence pour les calculs et les valeurs fournies par les événements.
Finalement il est possible de configurer quelles manipulations seront effectivement
suivies par WPF en fixant le
ManipulationMode via Manipulation.SetManipulationMode (c'est une propriété attachée). Les différentes valeurs sont :
- None : aucun événement n'est suivi,
- TranslateX : les translations sur l'axe X sont suivies,
- TranslateY : les translations sur l'axe Y sont suivies,
- Translate : les translations sur l'axe X et Y sont suivies,
- Rotate : les rotations sont suivies,
- Scale : les agrandisements/réductions sont suivies,
- All : TOUTES les manipulations sont suivies.
Réalisation pratique
Nous allons reproduire le comportement du scatterView comme cela avait
déjà été fait dans un précedent article en monotouch. Pour cela nous allons créer un bassin d'image au sein d'un canvas. Dans un premier temps on va s'abonner sur chacune des images ajoutées par souci de facilité. Les différentes actions sur les images seront réalisée à l'aide de la matrice de transformation
RenderTransform. Aussi, le manipulation container sera la fenêtre principale de l'application et cette valeur sera fixée dans l'événement
ManipulationStarting.
Voici le code de nôtre fenêtre :
<Window x:Class="MultiTouch.NET4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF-France - Multi touch .NET 4"
WindowState="Maximized">
<Canvas x:Name="CanvasDeDeplacement" Background="LightBlue">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="antoine.jpg" IsManipulationEnabled="True"
ManipulationStarting="Image_ManipulationStarting" ManipulationDelta="Image_ManipulationDelta"
ManipulationCompleted="Image_ManipulationCompleted" />
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="antoine.jpg" IsManipulationEnabled="True"
ManipulationStarting="Image_ManipulationStarting" ManipulationDelta="Image_ManipulationDelta"
ManipulationCompleted="Image_ManipulationCompleted" />
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="antoine.jpg" IsManipulationEnabled="True"
ManipulationStarting="Image_ManipulationStarting" ManipulationDelta="Image_ManipulationDelta"
ManipulationCompleted="Image_ManipulationCompleted" />
</Canvas>
</Window> Et voici le code behind de la fenêtre :
private void Image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
UIElement sendingElt = e.Source as UIElement;
Debug.WriteLine("La manipulation est en cours pour l'image.");
Matrix rectsMatrix = ((MatrixTransform)sendingElt.RenderTransform).Matrix;
// Tourne l'image
rectsMatrix.RotateAt(e.DeltaManipulation.Rotation,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);
// On retaille l'image
rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
e.DeltaManipulation.Scale.Y,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);
// On déplace l'image
rectsMatrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
// On applique la matrice à l'image
sendingElt.RenderTransform = new MatrixTransform(rectsMatrix);
}
private void Image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
//Très important : indique l'élément aucquels les calculs sont relatifs.
//Si il n'est pas fixé, la valeur par défaut est l'élement manipulé
e.ManipulationContainer = this;
Debug.WriteLine("La manipulation est commencée pour l'image.");
}
private void Image_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
Debug.WriteLine("La manipulation est terminée pour l'image.");
}
Amélioration de la mise en oeuvre
Comme on peut le voir, mettre en place les manipulations sur chaque élément est un peu fastidieux. On va donc utiliser les styles pour faciliter le tout. Voici le code XAML
amélioré :
<Canvas x:Name="CanvasDeDeplacement" Background="LightBlue">
<Canvas.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="IsManipulationEnabled" Value="True" />
</Style>
</Canvas.Resources>
<Canvas.Style>
<Style>
<EventSetter Event="UIElement.ManipulationStarting" Handler="Image_ManipulationStarting" />
<EventSetter Event="UIElement.ManipulationDelta" Handler="Image_ManipulationDelta" />
<EventSetter Event="UIElement.ManipulationCompleted" Handler="Image_ManipulationCompleted" />
</Style>
</Canvas.Style>
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="antoine.jpg" />
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="antoine.jpg" />
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="antoine.jpg" />
</Canvas>Dans un prochain article, nous étudierons comment améliorer encore cette petite application en ajoutant de l'inertie à nos images leur apportant ainsi un comportement plus
réél.
UIElements