2010-09-09 4 views
3

J'essaie de détecter le contrôle sous le curseur de la souris, que le contrôle soit activé ou non. Ignore les contrôles dont la propriété IsEnabled est définie sur false. Est-il possible de modifier ce comportement, ou tout autre moyen de trouver les contrôles à un emplacement d'écran spécifique?Existe-t-il un moyen de tester un contrôle désactivé?

Merci.

Répondre

1

Vous pouvez implémenter votre propre méthode récursive pour rechercher le sous-arbre et transformer chaque élément en racine visuelle de l'application afin d'obtenir ses bornes "absolues" puis tester si le point "absolu" est dans cette région.

Ce n'est peut-être pas exactement ce dont vous avez besoin mais qui devrait vous aider à démarrer. J'ai fondamentalement fait un remplacement FindElementsInHostCoordinates avec la même signature afin qu'il puisse être utilisé de la même manière dans votre gestionnaire MouseMove. Cette méthode essaie uniquement de "tester" les FrameworkElements, car elle doit connaître les propriétés ActualWidth et ActualHeight pour calculer la région touchée.

private IEnumerable<UIElement> FindAllElementsInHostCoordinates(Point intersectingPoint, UIElement subTree) 
{ 
    var results = new List<UIElement>(); 

    int count = VisualTreeHelper.GetChildrenCount(subTree); 

    for (int i = 0; i < count; i++) 
    { 
     var child = VisualTreeHelper.GetChild(subTree, i) as FrameworkElement; 

     if (child != null) 
     { 
      GeneralTransform gt = child.TransformToVisual(Application.Current.RootVisual as UIElement); 
      Point offset = gt.Transform(new Point(0, 0)); 
      Rect elementBounds = new Rect(offset.X, offset.Y, child.ActualWidth, child.ActualHeight); 

      if (IsInBounds(intersectingPoint, elementBounds)) 
      { 
       results.Add(child as UIElement); 
      } 
     } 

     results.AddRange(FindAllElementsInHostCoordinates(intersectingPoint, child)); 
    } 

    return results; 
} 

private bool IsInBounds(Point point, Rect bounds) 
{ 
    if (point.X > bounds.Left && point.X < bounds.Right && 
     point.Y < bounds.Bottom && point.Y > bounds.Top) 
    { 
     return true; 
    } 

    return false; 
} 

Vous aurez alors besoin juste pour vous assurer que le point que vous passez dans le gestionnaire MouseMove est par rapport à Application.Current.RootVisual:

IEnumerable<UIElement> elements = FindAllElementsInHostCoordinates(e.GetPosition(Application.Current.RootVisual), this); 
+0

Cela semble lent, mais je vais essayer. Je suis préoccupé par le fait que je ne serai pas en mesure de dire quand je pourrais obtenir un appel (probablement plus rapide) à FindElementsInHostCoordinates par rapport à l'utilisation de cette technique. – Greg

+0

Oui, vous marchez sur l'arbre visuel entier à chaque mouvement de souris, donc je suis sûr que la performance n'est pas excellente. Je ne suis pas sûr de ce que l'implémentation interne du vrai FindElementsInHostCoordinates ressemble mais je suis sûr qu'il y a des optimisations qui peuvent être faites. C'est juste la première chose qui m'est venue à l'esprit, peut-être qu'il y a une meilleure solution si la performance est une grande préoccupation dans votre application. –

+0

En fait, la performance semble bien, mais les résultats sont incorrects. Je reçois un certain nombre de contrôles dans ma liste de résultats lorsque je fais cela qui n'apparaissent pas lorsque j'utilise VisualTreeHelper.FindElementsInHostCoordinates(). Je n'ai pas encore compris comment décider quels éléments ne devraient pas figurer dans la liste. Avez-vous une idée du fonctionnement du hit-test d'exécution de Silverlight, en ce qui concerne la manière dont il décide des éléments à inclure dans sa liste? – Greg

Questions connexes