• Créer un conteneur WPF « draggable » (part 2)

    Où l'on commence l'implémentation du contrôle

    Pour commencer l'implémentation de ce contrôle, nous allons nous concentrer sur la détection du « gesture » : c'est assez simple, il suffit que l'utilisateur clique sur le contrôle et bouge d'au moins quelques pixels en maintenant le bouton gauche de la souris pour démarrer le drag/drop.

    Commençons par créer notre classe :

    using System;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows;
    
    namespace Carbenay.Michael.Controls
    {
        public class DraggableBorder : Border
        {
        }
    }

    Il faut ensuite détecter le mouvement de déclenchement :

    • Lorsque l'on clique sur l'élément (événement MouseDown) nous allons conserver la position de la souris
    • Lorsque l'on bouge la souris sur l'élément (évenement MouseMove) après ce clic, il faudra comparer la position de la souris actuelle par rapport a celle au moment de l'appui et si celle-ci est suffisamment différents – ce « suffisamment » étant défini par un paramètre de Windows – déclencher le drag/drop
    • Lorsque le bouton de la souris est relâché au dessus de l'élément (événement MouseUp), le drag/drop est annulé

    Pour être sûr de traiter les événements le plus tôt possible, nous n'allons pas vraiment nous connecter aux événements MouseDown, MouseMove, MouseUp mais à leur version « Preview » (pour plus de renseignement sur les événements et leur versions Preview, je vous conseille Application = Code + Markup de Charles Petzold) :

     

        public DraggableBorder()
        {
            PreviewMouseDown += new MouseButtonEventHandler(MyPreviewMouseDown);
            PreviewMouseMove += new MouseEventHandler(MyPreviewMouseMove);
            PreviewMouseUp += new MouseButtonEventHandler(MyPreviewMouseUp);
        }
        
        // position de la souris sur le MouseDown
        private Point _mouseDownPoint = new Point();
        // a true si le MouseDown a bien été détecté 
        // dans le controle
        private bool _wasMouseDownInControl = false;
    
        void MyPreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            // on "annule" le drag drop
            _wasMouseDownInControl = false;
        }
    
    
        void MyPreviewMouseMove(object sender, MouseEventArgs e)
        {
            // si le bouton gauche de la souris est toujours 
            // appuyé on regarde si la position actuelle
            // est suffisament eloignée de la position de
            // départ et si oui, on lance le drag/drop
            if (e.LeftButton == MouseButtonState.Pressed 
                && _wasMouseDownInControl)
            {
                Point pos = e.GetPosition(null);
    
                if (SystemParameters.MinimumHorizontalDragDistance <=
    Math.Abs(position.X - _mouseDownPoint.X) || SystemParameters.MinimumVerticalDragDistance <=
    Math.Abs(position.Y - _mouseDownPoint.Y)) { BeginDrag(); _wasMouseDownInControl = false; e.Handled = true; return; } } } void MyPreviewMouseDown(object sender, MouseButtonEventArgs e) { // on enregistre la position de la souris // pour détecter le mouvement de drag/drop _mouseDownPoint = e.GetPosition(null); _wasMouseDownInControl = true; }

    Reste la méthode BeginDrag dont le rôle est de préparer les données et de déclencher le drag/drop. Pour cette première version nous allons faire très simple et créer un objet de donnée avec une ligne de texte simple :

        private void BeginDrag()
        {
            DataObject data = new DataObject();
            data.SetData(DataFormats.Text, "Test");
            DragDropEffects de = DragDrop.DoDragDrop(this, 
                                    data, 
                                    DragDropEffects.Copy);
        }
    Au programme du prochain numéro : qu'est-ce que le DataObject et qu'est-il possible d'y mettre ?