2010-07-15 125 views
3

這個簡單的例子; 圖片由兩個重疊的元素A和B構成的維恩圖。 如果我將鼠標懸停在(A AND(NOT B))上,則A點亮。 如果我將鼠標懸停在(B AND(NOT A))上,所有的B都點亮。 如果我將鼠標放在(A和B)上,兩者應該點亮。只有最上面的標記爲鼠標懸停在上面。我可以讓WPF爲IsMouseOver覆蓋和覆蓋元素嗎?

有沒有辦法讓IsMouseOver像這樣隧道? 如果沒有,有什麼建議嗎?

回答

3

可以使用VisualTreeHelper做手工命中測試。這可以進入某個父對象的MouseMove處理程序。在這裏我假設作了題爲RedCircle和BlueCircle橢圓的維恩圖:

bool overRed = false; 
bool overBlue = false; 
if (BlueCircle.IsMouseOver || RedCircle.IsMouseOver) 
{ 
    HitTestParameters parameters = new PointHitTestParameters(e.GetPosition(RedCircle)); 
    VisualTreeHelper.HitTest(RedCircle, new HitTestFilterCallback(element => HitTestFilterBehavior.Continue), result => 
    { 
     if (result.VisualHit == RedCircle) 
      overRed = true; 
     return HitTestResultBehavior.Continue; 
    }, parameters); 

    parameters = new PointHitTestParameters(e.GetPosition(BlueCircle)); 
    VisualTreeHelper.HitTest(BlueCircle, new HitTestFilterCallback(element => HitTestFilterBehavior.Continue), result => 
    { 
     if (result.VisualHit == BlueCircle) 
      overBlue = true; 
     return HitTestResultBehavior.Continue; 
    }, parameters); 
} 
+0

缺失的部分是何時擊中測試。這將因情況而異。另外,您需要從重疊對象的聯合父項進行測試。雖然在我的玩具例子中這沒有問題,但在我的真實情況下,我必須穿過邏輯樹中的共同父親的根。謝謝! – Ball 2010-07-21 12:27:13

0

使用IsMouseDirectlyOver屬性。這似乎是你需要的東西。

http://msdn.microsoft.com/en-us/library/system.windows.uielement.ismousedirectlyoverproperty.aspx

+3

其實,這不是它。如果有任何來自子元素的遮擋,則IsMouseDirectlyOver爲false。對於IsMouseOver,子元素不計數,只是父母的邊界。 IsMouseDirectlyOver更具體。由於我的維恩圈子之間沒有任何兒童關係,因此我希望能夠直接瞭解什麼是直接結束。 – Ball 2010-07-15 19:54:34

0

我需要類似的東西在我的項目,並颳起了快速的解決方案。

public sealed class IsMouseOverEnchancementBehavior 
    { 
     #region MouseCurrentPosition 

     internal sealed class MouseCurrentPosition 
     { 
      private Point _currentPosition; 
      private readonly Timer _timer = new Timer(250); 

      public event EventHandler<EventArgs> PositionChanged; 

      public MouseCurrentPosition() 
      { 
       _timer.Elapsed += timer_Elapsed; 
       _timer.Start(); 
      } 

      public Point CurrentPosition 
      { 
       get { return _currentPosition; } 

       set 
       { 
        if (_currentPosition != value) 
        { 
         _currentPosition = value; 
         var pos = PositionChanged; 
         if (pos != null) 
          PositionChanged(null, null); 
        } 
       } 
      } 

      [DllImport("user32.dll")] 
      [return: MarshalAs(UnmanagedType.Bool)] 
      private static extern bool GetCursorPos(ref NativePoint pt); 

      public static Point GetCurrentMousePosition() 
      { 
       var nativePoint = new NativePoint(); 
       GetCursorPos(ref nativePoint); 
       return new Point(nativePoint.X, nativePoint.Y); 
      } 

      private void timer_Elapsed(object sender, ElapsedEventArgs e) 
      { 
       Point current = GetCurrentMousePosition(); 
       CurrentPosition = current; 
      } 

      [StructLayout(LayoutKind.Sequential)] 
      internal struct NativePoint 
      { 
       public int X; 
       public int Y; 
      }; 
     } 

     #endregion 

     private static readonly MouseCurrentPosition _mouseCurrentPosition = new MouseCurrentPosition(); 


     public static DependencyProperty IsMouseOverIgnoreChild = 
      DependencyProperty.RegisterAttached("IsMouseOverIgnoreChild", typeof (bool), 
       typeof (IsMouseOverEnchancementBehavior), 
       new FrameworkPropertyMetadata(false)); 

     public static readonly DependencyProperty IsMouseOverEnchancementEnabled = 
      DependencyProperty.RegisterAttached("IsMouseOverEnchancementEnabled", 
       typeof (bool), typeof (IsMouseOverEnchancementBehavior), 
       new UIPropertyMetadata(false, OnMouseOverEnchancementEnabled)); 

     private static void OnMouseOverEnchancementEnabled(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      // todo: unhook if necessary. 
      var frameworkElement = (FrameworkElement) d; 
      DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(UIElement.IsMouseOverProperty, 
       typeof (UIElement)); 


      Action calculateCurrentStateAction =() => 
      { 
       // cheap check. 
       if (frameworkElement.IsMouseOver) 
       { 
        SetIsMouseOverIgnoreChild(frameworkElement, true); 
        return; 
       } 

       // through hit-testing. 
       var isMouseOver = VisualTreeHelper. 
        HitTest(frameworkElement, Mouse.GetPosition(frameworkElement)) != null; 

       SetIsMouseOverIgnoreChild(frameworkElement, isMouseOver); 
      }; 

      // if the mose moves, 
      // we shall re-do hit testing. 
      _mouseCurrentPosition.PositionChanged += delegate 
      { 
       frameworkElement.Dispatcher.Invoke(
        calculateCurrentStateAction); 
      }; 

      // If IsMouseOver changes, 
      // we can propagate it to our property. 
      dpd.AddValueChanged(frameworkElement, 
       delegate { calculateCurrentStateAction(); }); 
     } 

     #region Misc 

     public static bool GetIsMouseOverEnchancementEnabled(DependencyObject obj) 
     { 
      return (bool) obj.GetValue(IsMouseOverEnchancementEnabled); 
     } 

     public static void SetIsMouseOverEnchancementEnabled(DependencyObject obj, bool value) 
     { 
      obj.SetValue(IsMouseOverEnchancementEnabled, value); 
     } 


     public static bool GetIsMouseOverIgnoreChild(DependencyObject obj) 
     { 
      return (bool) obj.GetValue(IsMouseOverIgnoreChild); 
     } 

     public static void SetIsMouseOverIgnoreChild(DependencyObject obj, bool value) 
     { 
      obj.SetValue(IsMouseOverIgnoreChild, value); 
     } 

     #endregion 
    } 

這是一個更通用的解決方案,使用計時器。

這是我如何使用它的風格:

<Setter Property="behaviors:IsMouseOverEnchancementBehavior. 
      IsMouseOverEnchancementEnabled" Value="True" /> 

<Style.Triggers> 

    <!-- Just a visual feedback --> 
    <!-- Let the user know that mouse is over the element --> 
    <!-- When we are in editmode --> 
    <MultiTrigger> 
     <MultiTrigger.Conditions> 
      <Condition Property="IsInEditMode" Value="True" /> 
      <Condition Property="behaviors:IsMouseOverEnchancementBehavior.IsMouseOverIgnoreChild" Value="True" /> 
     </MultiTrigger.Conditions> 
     ...do stuff here....