我可以为覆盖元素和覆盖元素制作WPF设置IsMouseOver吗?

时间:2010-07-15 19:22:33

标签: wpf

简化示例; 图片由两个元素A和B组成的维恩图,它们重叠。 如果我鼠标悬停(A AND(不是B))A全部亮起。 如果我鼠标悬停(B AND(不是A))所有B都亮起来。 如果我鼠标悬停(A和B),两者应该亮起来。只有最顶部标记为鼠标悬停在它上面。

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

3 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:0)

使用IsMouseDirectlyOver属性。这似乎是你需要的东西。

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

答案 2 :(得分: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....
相关问题