2010-04-13 5 views
13

J'ai une opération de glisser-déposer sur un canevas qui est censé faire quelque chose quand un objet est traîné dans et hors de celui-ci. Mon problème est que les événements DragEnter/DragLeave ne cessent de se déclencher lorsque la souris déplace l'objet sur elle, pas seulement sur entrée/sortie. Plus la souris se déplace rapidement, plus les événements se déclenchent fréquemment. L'événement DragOver Canvas déplace le Canvas.Top/Left du DraggedObject et je pense que cela pourrait être mon problème, mais je ne suis pas sûr de savoir comment résoudre ce problème.DragDrop - Les événements DragEnter/DragLeave continuent de se déclencher

+0

Vous avez probablement raison, si vous nous dites _why_ que vous voulez faire cela, nous pouvons peut-être proposer une alternative. –

+0

J'ai une toile avec un groupe de panneaux dessus. Les panneaux peuvent être déplacés pour les réorganiser, ou de nouveaux peuvent être ajoutés en faisant glisser un nouveau panneau à partir d'une zone de liste sur le canevas. Ils peuvent également être supprimés en faisant glisser les panneaux hors du canevas et retour à la zone de liste. – Rachel

Répondre

15

Voici la séquence des événements:

  1. Votre souris se déplace de l'endroit où vous avez cliqué sur ce à travers le panneau. Aucun événement ne tire.
  2. Votre souris atteint le bord du panneau et pénètre dans le canevas. L'événement DragEnter se déclenche sur le canevas. Votre gestionnaire DragEnter déplace le Panel pour qu'il soit maintenant sous la souris. Étant donné que la souris n'est plus sur le canevas (il est sur le panneau), l'événement DragLeave se déclenche.
  3. Votre souris se déplace plus loin, atteignant à nouveau le bord du panneau. Les étapes 2 et 3 se répètent.

Plus vous déplacez la souris rapidement, plus vous recevrez d'événements.

L'essence de votre problème est que glisser-déposer utilise des tests a frappé, et en déplaçant votre panneau vous défaisant la capacité de test de recherche pour voir « derrière » votre panneau pour savoir ce conteneur, il est tombé dans.

La solution est d'utiliser votre propre code pour le glisser-déposer, ce qui n'est vraiment pas difficile du tout. Le moteur de test de succès de WPF est assez puissant pour effectuer des tests de hit derrière l'objet actuel, mais le glisser-déposer n'utilise pas cette fonctionnalité. Vous pouvez l'utiliser directement en utilisant la surcharge VisualTreeHelper.HitTest qui prend un HitTestFilterCallback et un HitTestResultCallback. Il suffit de lui passer un filtre qui ignore les hits dans le panneau en train d'être déplacé. J'ai découvert que pour des scénarios comme vous le décrivez, faire glisser-déposer en manipulant des événements de souris est en fait plus facile que d'utiliser le DoDragDrop intégré car vous n'avez pas à gérer la complexité (DataObject, DragDropEffects, QueryContinueDrag, etc). Cette complexité supplémentaire est très importante pour permettre des scénarios de glisser entre les applications et les processus, mais ne vous aide pas pour ce que vous faites.

est ici la solution simple:

  1. Sur MouseDown avec le bouton gauche vers le bas, enregistrer la position (sur MouseLeave effacer la position)
  2. Sur MouseMove avec {bouton gauche, la position enregistrée, diffère de la position de la souris en cours par plus de delta} définir un drapeau indiquant que l'opération de dragage est en cours & capturer la souris
  3. Sur MouseMove avec une opération de glissement en cours, utilisez le test d'impact pour déterminer l'emplacement de votre panneau (sans tenir compte du panneau lui-même) et ajuster sa fonction parentale. position en conséquence.
  4. Sur MouseUp avec l'opération de glisser en cours, relâchez la capture de la souris et désactivez la « opération de glissement est en cours » drapeau

Profitez.

+0

Merci, c'est exactement ce que je cherchais! J'ai converti mes propriétés glisser/déposer pour utiliser MouseEvents au lieu de DragEvents et cela m'a donné les résultats que je recherchais. J'avais quelques soucis à l'origine parce que je traînais des objets de databound et des classes personnalisées, mais ils sont tous très bien passés. – Rachel

2

Je trouve nécessaire d'ajouter une réponse plus précise à ce qui se passe, je vais ajouter cette même réponse dans d'autres questions liées à ce problème également.

Ok, voici ce qui se passe:

  1. Vous créez une opération de glisser-déposer.
  2. Pendant que vous faites un glisser-déposer, vous voulez que quelque chose de visuel s'affiche le long de votre souris.
  3. Cet élément visuel est en cours d'ajout à une grille ou un panneau sur l'événement Drag-Enter et en cours de suppression sur l'événement Drag-Leave.
  4. Quand il est placé sous la souris, vous obtenez un événement congé de glisser comme l'élément dessin que vous vole effectivement l'opération de glisser-déposer ..

Solution: Assurez-vous que IsEnabled=false pour l'élément que vous dessiner sous la souris.
De cette façon, il ne capture pas l'opération de glisser-déposer et vous n'obtiendrez pas d'effet de scintillement.

2

C'est un peu vieux, mais j'ai eu le même problème. J'utilisais un adorateur pour indiquer où traînait un objet traîné. Je permettrait au Adorner dans DragEnter, puis immédiatement enregistrer un DragLeave et désactiver le Adorner, puis un DragEnter ...

IsEnabled = false ne fonctionne pas pour moi, mais IsHitTestVisible = false a fait. Je mets cela dans le constructeur de mon Adorner, et maintenant tout fonctionne à merveille:

public DragDropAdorner(UIElement adornedElement) : base(adornedElement) 
{ 
    _layer = AdornerLayer.GetAdornerLayer(AdornedElement); 
    _layer.IsEnabled = false; 
    _layer.IsHitTestVisible = false; 
} 
+0

Cette solution simple a effectivement fonctionné pour moi et était adapté à mes besoins. Je vous remercie. –

Questions connexes