Détection de mouvement sur un Panorama WP7

La détection du mouvement d’un panorama peut être intéressant dans certain cas.

Par exemple :

  • Pour mettre un voile gris sur l’application lorsque le panorama est en mouvement (comme le hub office)
  • Pour empêcher des actions lors du mouvement (click intempestif sur des boutons).
  • Dans cet article nous tenterons de mettre en place un voile lors du déplacement de notre panorama.

    Malheureusement, il n’existe pas de propriété indiquant que le panorama est en train de bouger.
    Nous allons donc rajouter une propriété IsMoving sur le controle Panorama.

    On ajoute tout d’abord une classe PanormaExtender à notre solution « Window Phone Panorama Project »

    Pour effectuer une implémentation réutilisable on utilisera les AttachedProperty (via le snippet propa).
    On ajoute maintenant la propa IsMoving dans la classe. Celle ci sera chargé de nous communiqué si le panorama est train de bougé. Du fait de sa nature (AttachedProperty), cette propriété est bindable

            
            /// <summary>
            /// Le panorama est en train de bouger
            /// </summary>
            /// <param name="obj"></param>
            /// <returns></returns>
    
            public static bool GetIsMoving(DependencyObject obj)
            {
                return (bool)obj.GetValue(IsMovingProperty);
            }
    
            public static void SetIsMoving(DependencyObject obj, bool value)
            {
                obj.SetValue(IsMovingProperty, value);
            }
    
            // Using a DependencyProperty as the backing store for IsMoving.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsMovingProperty =
                DependencyProperty.RegisterAttached("IsMoving", typeof(bool), typeof(PanoramaExtender), new PropertyMetadata(false));
    

    Pour mettre en place la détection ou non des mouvement du panorama, nous devons mettre en place une nouvelle propriété attaché que nous appellerons CanDetectMovement :

            public static bool GetCanDetectMovement(DependencyObject obj)
            {
                return (bool)obj.GetValue(CanDetectMovementProperty);
            }
    
            public static void SetCanDetectMovement(DependencyObject obj, bool value)
            {
                obj.SetValue(CanDetectMovementProperty, value);
            }
    
            // Using a DependencyProperty as the backing store for CanDetectMovement.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty CanDetectMovementProperty =
                DependencyProperty.RegisterAttached("CanDetectMovement", typeof(bool), typeof(PanoramaExtender), new PropertyMetadata(false, OnCanDetectMovementChanged));
    

    La particularité de cette propriété est qu’elle doit nous abonner aux évenements nécessaire à la détection du mouvement. Cette mise en place sera effectué via la méthode OnCanDetectMovementChanged.

            private static void OnCanDetectMovementChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                Panorama panorama = sender as Panorama;
    
                if (panorama != null)
                {
                    bool canDetectMovement = (bool)e.NewValue;
    
                    if (canDetectMovement == true)
                    {
                        panorama.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(panorama_ManipulationDelta);
                        panorama.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(panorama_ManipulationCompleted);
                    }
                    else
                    {
                        panorama.ManipulationDelta -= new EventHandler<ManipulationDeltaEventArgs>(panorama_ManipulationDelta);
                        panorama.ManipulationCompleted -= new EventHandler<ManipulationCompletedEventArgs>(panorama_ManipulationCompleted);
                    }
                }
            }
    

    Passons maintenant à la détection proprement dite. Celle ci est effectuée via les evenements ManipulationDelta et ManipulationCompleted.

    L’évenement ManipulationDelta nous permet de détecter si un mouvement est effectué sur le panorama. Pour détecter le nombre de pixel qui ont été bougé depuis le début du mouvement on utilise la propriété CumulativeManipulation.Translation.X de l’argument. Ainsi si le déplacement de cette propriété est de 5 pixels, nous pouvons considérer qu’il y a déplacement. Si il y a deplacement, on fixe la propriété attaché IsMoving à true. Inutile ensuite de continuer à effectuer le test.

            static void panorama_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
            {
                Panorama panorama = sender as Panorama;
    
                if ((bool)panorama.GetValue(PanoramaExtender.IsMovingProperty) == false)
                {
                    if (Math.Abs(e.CumulativeManipulation.Translation.X) > 5)
                    {
                        panorama.SetValue(PanoramaExtender.IsMovingProperty, true);
                    }
                }
             }
    

    Il ne nous reste plus qu’à attendre que le mouvement se termine (ManipulationCompleted) pour fixer le IsMoving à false.

            static void panorama_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
            {
                Panorama panorama = sender as Panorama;
                panorama.SetValue(PanoramaExtender.IsMovingProperty, false);
            }
    

    coté XAML, on rajoute le namespace extenders :

        xmlns:extenders="clr-namespace:Extenders"
    

    puis dans le Panorama les deux propriétés attachées :

    <controls:Panorama x:Name="Panorama" Title="my application" extenders:PanoramaExtender.CanDetectMovement="True" extenders:PanoramaExtender.IsMoving="False">
    ...
    </controls:Panorama>
    

    Pour mettre en place le voile de l’application on rajoute un rectangle devant le panorama et on binde sa propriété Visibility sur l’element Panorama de Path (extenders:PanoramaExtender.IsMoving). Un petit convertisseur de boolean vers l’enum Visibility est utilisé pour permettre ou non l’affichage du voile.

            
    

    vous trouverez le projet complet de cet article ici et la classe Panorama extender seule ici.

    leave your comment