WPF France

  • Augmenter la taille
  • Taille par défaut
  • Diminuer la taille

MultiTouch : ces contrôles suivent mes doigts ! [.NET 4.0]

Envoyer Imprimer PDF
Note des utilisateurs: / 2
MauvaisTrès bien 
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 :
  1. None : aucun événement n'est suivi,
  2. TranslateX : les translations sur l'axe X sont suivies,
  3. TranslateY : les translations sur l'axe Y sont suivies,
  4. Translate : les translations sur l'axe X et Y sont suivies,
  5. Rotate  : les rotations sont suivies,
  6. Scale : les agrandisements/réductions sont suivies,
  7. 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
Commentaires (0)
Mise à jour le Vendredi, 07 Mai 2010 13:12  

Partagez


Article au hasard

  • Imaginons un scénario très simple: je dispose d’une interface graphique me permettant d’afficher une propriété, de type int mais étant en plus nullable.
    Si la valeur n'est pas affectée, rien n'est affiché une fois utilisé dans l'interface. Commentaires (0)...
    Lire la suite...