Can I make WPF installed IsMouseOver both for coverage and for covered item?

A simplified example of this; draw a Venn diagram made up of two elements, A and B, that overlap. If I ply over (A AND (NOT B)), all A lights up. If I am above (B AND (NOT A)), all B lights up. If I hover over (A AND B), BOTH should light up. Only the upper part of the most marked as having a cursor over it.

Is there a way to allow IsMouseOver tunnel? If not, any suggestions?

+3
source share
3 answers

You can perform manual testing using VisualTreeHelper. It could be a MouseMove handler on some parent object. Here I take a Venn diagram from ellipses called RedCircle and 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);
}
+3
source
0
source

- .

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

Source: https://habr.com/ru/post/1754874/


All Articles