2010-12-01 7 views
2

J'ai le code suivantHit comportement Test

public partial class MainWindow : Window 
{ 
    public MainWindow() { 
     InitializeComponent(); 
    } 

    List<UIElement> ucs = new List<UIElement>(); 

    private void Window_PreviewMouseLeftButtonDown(object sender, 
     MouseButtonEventArgs e) 
    { 
     ucs.Clear(); 

     Point p = e.GetPosition((UIElement)sender); 

     VisualTreeHelper.HitTest(this, null, 
      new HitTestResultCallback(MyHitTestCallback), 
      new PointHitTestParameters(p)); 

     Console.WriteLine("ucs.Count = {0}", ucs.Count); 

     foreach (var item in ucs) 
     { 
      Console.WriteLine("item: {0}", item.ToString()); 
     } 
    } 

    HitTestResultBehavior MyHitTestCallback(HitTestResult result) 
    { 
     ucs.Add(result.VisualHit as UIElement); 
     return HitTestResultBehavior.Continue; 
    } 
} 

c'est ma fenêtre

<Window> 
    <Grid> 
     <my:UserControl1 HorizontalAlignment="Left" Margin="82,88,0,0" x:Name="userControl11" VerticalAlignment="Top" /> 
     <my:UserControl1 HorizontalAlignment="Left" Margin="168,166,0,0" x:Name="userControl12" VerticalAlignment="Top" /> 
     <my:UserControl1 HorizontalAlignment="Left" Margin="231,130,0,0" x:Name="userControl13" VerticalAlignment="Top" /> 
    </Grid> 
</Window> 

c'est mon UC

<UserControl> 
    <Grid> 
     <Label Content="Label" Height="44" HorizontalAlignment="Left" Name="label1" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="78" Background="#FF4B9FC4" BorderBrush="#FF020A0D" BorderThickness="1" /> 
    </Grid> 
</UserControl> 

c'est la sortie lorsque je clique sur un utilisateur CONTROL, puis à une intersection de 2 UserControls:

ucs.Count = 2 
item: System.Windows.Controls.Border 
item: System.Windows.Controls.Border 
ucs.Count = 3 
item: System.Windows.Controls.Border 
item: System.Windows.Controls.Border 
item: System.Windows.Controls.Border 

Pourquoi cela? Où est UserControl sous l'instance de la souris?

PS:
Maintenant, quand j'ai sur l'étiquette le BorderThickness = 0

ucs.Count = 3 
item: System.Windows.Controls.TextBlock 
item: System.Windows.Controls.Border 
item: System.Windows.Controls.Border 
ucs.Count = 3 
item: System.Windows.Controls.TextBlock 
item: System.Windows.Controls.Border 
item: System.Windows.Controls.Border 

Répondre

2

Le UserControl1 est invisible. Ses contenus sont visibles, mais votre instance UserControl1 elle-même n'a aucun visuel propre. (Et ce ne sera jamais le cas, le travail d'un contrôle utilisateur consiste simplement à contenir d'autres choses.)

Les tests de réussite ne signalent que les éléments qui contribuent directement à l'arborescence visuelle. Et puisque le test de coupure considère chaque élément isolément, cela signifie que les éléments qui agissent uniquement comme des conteneurs n'apparaissent pas. (Et un fait connexe est que le test de hit ne considère que les pixels qui ont réellement été peints.) Donc, si vous avez un Border où vous avez défini le BorderBrush et un BorderThickness non nul, mais vous n'avez pas de Background, le test de Le contour de la bordure sera considéré comme un hit - les points à l'intérieur de la bordure ne seront pas considérés comme frappant la frontière, car ils ne peindront rien à l'intérieur

Si vous avez besoin de faire un test de hit d'une "chose", ou quoi que ce soit à l'intérieur chose » le style, alors soit soit

  1. utiliser la souris Entrée/laisser les événements - les bulles, et donc ils seront même soulevé sur les éléments de conteneurs invisibles
  2. utilisation IsMouseOver ou
  3. utiliser la fonction de test de recherche que vous utilisez, passer le contrôle de l'utilisateur comme premier argument, et traiter tout coup comme une indication que le point de test de recherche dans le contrôle de l'utilisateur

Le troisième est plus complexe, mais si vous avez besoin de toucher des points de test autres que celui actuellement sous la souris, vous devrez l'utiliser.

+0

J'ai besoin de compter tous les MyUserControls sous la souris, directement ou indirectement sous le curseur de la souris. IsMouseOver ne retournera vrai que si l'élément est * directement * sous la souris. – serhio

+0

Qu'entendez-vous par "indirectement"? IsMouseOver est documenté comme "incluant les éléments enfants visuels qui sont à l'intérieur de ses limites". Je me demande si vous cherchez un confinement de boîte englobante, auquel cas le test de coup est une mauvaise chose. Pour cela, vous voulez juste VisualTreeHelper.GetDescendantBounds. –

+0

... ou pour le dire autrement, je pense que WPF hit test fait probablement quelque chose de différent de ce que vous voulez. Pourriez-vous décrire ce que vous voulez faire, sans utiliser l'expression «essai de succès» parce que je pense que l'ambiguïté de ce terme est ce qui cause la confusion ici. –