代码之家  ›  专栏  ›  技术社区  ›  Ball

我可以为覆盖元素和覆盖元素制作wpf set ismouseover吗?

wpf
  •  3
  • Ball  · 技术社区  · 14 年前

    这个简化的例子; 想象一个由两个重叠元素A和B构成的维恩图。 如果我把鼠标移到(A和(不是B)上,所有A灯都会亮起来。 如果我把鼠标移到(b和(不是a))上,所有b都会亮起。 如果我把鼠标移到(A和B)上,两者都应该亮起来。只有最上面的被标记为有鼠标在上面。

    有没有办法让Ismouseover这样挖隧道? 如果没有,有什么建议吗?

    3 回复  |  直到 10 年前
        1
  •  3
  •   John Bowen    14 年前

    您可以使用VisualTreeHelper执行手动命中测试。这可以进入某个父对象上的mousemove处理程序。这里我假设一个由椭圆构成的维恩图,叫做红圆和蓝圆:

    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);
    }
    
        2
  •  0
  •   STO    14 年前
        3
  •  0
  •   Erti-Chris Eelmaa    10 年前

    在我的项目中,我需要一些类似的东西,并迅速想出一个解决方案。

    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....