Могу ли я сделать WPF установить IsMouseOver как для покрытия, так и для элемента покрытия? - PullRequest
3 голосов
/ 15 июля 2010

Упрощенный пример этого;представьте диаграмму Венна, состоящую из двух перекрывающихся элементов A и B.Если я наведу курсор на (A И (НЕ B)), все A загорается.Если я наведу курсор мыши на (B AND (НЕ A)), все B загораются.Если я наведу курсор мыши (A и B), ОБА должны загореться.Только самая верхняя часть помечается как наведенная на нее мышью.

Есть ли способ разрешить IsMouseOver туннелировать так?Если нет, то есть предложения?

Ответы [ 3 ]

3 голосов
/ 16 июля 2010

Вы можете выполнить ручное тестирование, используя 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 голосов
/ 30 декабря 2014

Мне нужно что-то похожее в моем проекте, и я нашел быстрое решение.

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 голосов
/ 15 июля 2010

Используйте свойство IsMouseDirectlyOver.Кажется, вам нужна вещь.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...