c# wpf chevauchement des contrôles de ne pas recevoir les événements de la souris
Je suis la construction d'un contrôle de zone de dessin. Cette racine toile a plusieurs chevauchement des enfants (de la toile). Ceci est fait de sorte que chaque enfant peut gérer son propre dessin et je peux composez ensuite le résultat final avec tous les enfants pour obtenir le comportement souhaité.
Cela fonctionne très bien autant que le rendu est concerné. Cela ne fonctionne pas si bien avec les événements de la souris. La façon dont les événements de la souris œuvres sont comme suit (en utilisant previewmousemove à titre d'exemple):
1 - Si la racine de la toile est sous la souris, le feu de l'événement
2 - Vérifier tous les enfants, si l'on est sous la souris, le feu de l'événement et arrêter
En tant que tel, seul le premier enfant, j'ai ajouter recevrez le déplacement de la souris de l'événement. L'événement n'est pas propagée à tous les enfants, parce qu'ils se chevauchent.
Pour remédier à cela, j'ai tenté le suivant:
1 - Remplacer les événements de la souris dans la racine de la toile
2 - Pour chaque événement, tous les enfants qui veulent gérer l'événement à l'aide de VisualTreeHelper.HitTest
3 - Pour tous les enfants qui ont retourné un valide frappé résultat du test (c'est à dire: en vertu de la souris et prêt à gérer l'événement (IsHitTestVisible == true)), ???
C'est là que je suis bloqué, j'ai en quelque sorte besoin d'envoyer l'événement de la souris à tous les enfants, et d'arrêter le flux normal de l'événement pour s'assurer le premier enfant de ne pas recevoir deux fois (via traitées = true dans le cas).
En utilisant RaiseEvent avec le même événement se passa sur les enfants, les choses semblent fonctionner mais de toute façon il déclenche l'événement sur le parent (racine de la toile). Pour contourner cela, j'avais besoin de créer une copie de l'événement et de l'ensemble de la force de définir la source même s'il semble être plus un hack qu'une solution. Est-il une bonne façon de faire ce que je suis en train de faire? Exemple de Code qui suit.
public class CustomCanvas : Canvas
{
private List<object> m_HitTestResults = new List<object>();
public new event MouseEventHandler MouseMove;
public CustomCanvas()
{
base.PreviewMouseMove += new MouseEventHandler(CustomCanvas_MouseMove);
}
private void CustomCanvas_MouseMove(object sender, MouseEventArgs e)
{
//Hack here, why is the event raised on the parent as well???
if (e.OriginalSource == this)
{
return;
}
Point pt = e.GetPosition((UIElement)sender);
m_HitTestResults.Clear();
VisualTreeHelper.HitTest(this,
new HitTestFilterCallback(OnHitTest),
new HitTestResultCallback(OnHitTest),
new PointHitTestParameters(pt));
MouseEventArgs tmpe = new MouseEventArgs(e.MouseDevice, e.Timestamp, e.StylusDevice);
tmpe.RoutedEvent = e.RoutedEvent;
tmpe.Source = this;
foreach (object hit in m_HitTestResults)
{
UIElement element = hit as UIElement;
if (element != null)
{
//This somehow raises the event on us as well as the element here, why???
element.RaiseEvent(tmpe);
}
}
var handlers = MouseMove;
if (handlers != null)
{
handlers(sender, e);
}
e.Handled = true;
}
private HitTestFilterBehavior OnHitTest(DependencyObject o)
{
UIElement element = o as UIElement;
if (element == this)
{
return HitTestFilterBehavior.ContinueSkipSelf;
}
else if (element != null && element.IsHitTestVisible && element != this)
{
return HitTestFilterBehavior.Continue;
}
return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
}
private HitTestResultBehavior OnHitTest(HitTestResult result)
{
//Add the hit test result to the list that will be processed after the enumeration.
m_HitTestResults.Add(result.VisualHit);
//Set the behavior to return visuals at all z-order levels.
return HitTestResultBehavior.Continue;
}
Est-ce pour silverlight? WPF? Ajouter des tags pertinents, vous obtiendrez une réponse plus rapide.
OriginalL'auteur | 2009-04-11
Vous devez vous connecter pour publier un commentaire.
Je pense que vous devriez utiliser l'aperçu des événements, car ceux-ci sont RoutingStrategy.Tunnel à partir de la Fenêtre de la plus haute de contrôle dans l'Ordre-Z, et des événements normaux sont RoutingStrategy.La bulle.
Dans ce RoutedEvents il y a un bien Gérer quand il est vrai que le système va s'arrêter pour parcourir l'arborescence visuelle parce que quelqu'un a utilisé cet événement.
OriginalL'auteur GuerreroTook
J'ai trouvé votre exemple de code intéressant donc j'ai essayé... mais j'ai dû faire une petite modification pour que cela fonctionne correctement dans mes trucs.
J'ai dû changer la 2ème "si" dans le HitTestFilter méthode comme suit:
Comme vous pouvez le voir, j'ai enlevé l'inutile "element != ce" à la fin (vous déjà testé cette condition dans le 1er "si") et j'ai ajouté "element == null" au début.
Pourquoi? Parce qu'à un certain point pendant le filtrage du type de paramètre a été Système.De Windows.Médias.ContainerVisual qui n'héritent pas de UIElement et donc élément devra être mis à null et ContinueSkipSelfAndChildren serait renvoyé. Mais je ne veux pas sauter les enfants parce que ma Toile est contenue à l'intérieur de ses "Enfants" de collecte et de UIElements je veux hittest sont contenues dans la Toile.
OriginalL'auteur SuperOli
Tout comme @GuerreroTook dit, vous devez résoudre ce problème en utilisant WPF RoutedEvents (plus d'informations ici.
OriginalL'auteur Jonas Van der Aa