WPF:鼠标离开事件不发生';鼠标按下时不要触发

WPF:鼠标离开事件不发生';鼠标按下时不要触发,wpf,events,mouse,Wpf,Events,Mouse,我对鼠标进入/离开事件有问题。当光标在控件内按住鼠标按钮,然后光标以足够快的速度移出控件时,不会触发此事件 你能告诉我为什么会这样吗?有没有办法正确获取这些事件 请检查示例项目以查看其实际情况: 更新。我发现同样的问题没有答案。从那里开始赏金。这是“正常”行为。在MouseEnter处理程序中捕获鼠标 Mouse.Capture(yourUIElement); 然后在MouseLeave中释放它 Mouse.Capture(null); 编辑:更多解释。 WPF不能精确跟踪鼠标移动。从以下事

我对鼠标进入/离开事件有问题。当光标在控件内按住鼠标按钮,然后光标以足够快的速度移出控件时,不会触发此事件

你能告诉我为什么会这样吗?有没有办法正确获取这些事件

请检查示例项目以查看其实际情况:

更新。我发现同样的问题没有答案。从那里开始赏金。

这是“正常”行为。在MouseEnter处理程序中捕获鼠标

Mouse.Capture(yourUIElement);
然后在MouseLeave中释放它

Mouse.Capture(null);
编辑:更多解释。 WPF不能精确跟踪鼠标移动。从以下事实可以推断,如果捕获MouseMove事件,您可以看到它每隔20毫秒报告一次事件,而不是按像素精度。。更像是每个事件8个像素

这并不可怕,但是WPF也不会报告鼠标在窗口外的移动,如果你碰巧移动了鼠标。这是默认行为。你可以通过鼠标来改变它。如前所述捕获

现在,你可以想象为什么会发生这个问题。如果在窗口外移动鼠标的速度比鼠标移动报告发生的速度快,那么WPF仍然认为它在应用程序内部

方法#1-如果您能解决具体问题,它仍然是一种有效的方法(作为一种纯管理解决方案)。
(可以将捕获交给特定控件以避免问题,但我没有尝试)

这将帮助您获取事件(“已修复”事件)

关键是在窗口外跟踪鼠标移动(仅当鼠标按下时)

为此,您需要执行
捕获
(但与建议的稍有不同,因为这不起作用-改为向下/向上)

注:
你需要根据你的情况完成这件事。我刚刚“虚拟连线”鼠标移动到
Enter
Leave
,没有任何智能算法(即
生成的
Enter/Leave将继续启动)。也就是说,添加一些标志以正确保存进入/离开的
状态

我还测量鼠标是否在窗口的“客户端边界”内。如果你需要在边界等方面进行调整,你需要调整


另外,我忘了添加明显的-连接新事件
MouseDown=“Window\u MouseDown”MouseUp=“Window\u MouseUp”

编辑:在Sisyphe正确地指出该行为不适用于具有鼠标交互的元素之后,我重写了代码

该行为可以附加到窗口或任何其他框架元素。默认情况下,当鼠标左键按下并执行处理程序时,将监视包含的所有元素的MouseLeave。通过设置
monitorSubcrols=“False”
,该行为也可以仅应用于其关联的元素

行为的基本功能(有关更多详细信息,请参阅代码中的注释):

  • 仅当按下鼠标左键时才“激活”
  • 观察鼠标位置在元素内部到外部的变化。在本例中,执行事件处理程序
已知的局限性(我认为,这些都可以通过更多的努力来解决,但对我来说似乎不太重要):

  • 不执行转换到包含元素(“内部”边界)的处理程序
  • 不保证处理程序的正确执行顺序
  • 无法解决向窗口外部缓慢过渡的问题,例如,LeftButton被报告为已发布(错误?)
  • 我决定不使用Win32钩子,而是使用一个计时器,它不会超过每0.15秒触发一次(尽管设置的间隔较小,时钟漂移?)。对于快速鼠标移动,评估的点可能相距太远,并错过刚刚掠过的元素

此脚本生成以下输出:将行为附加到窗口,在orangeBorder内部移动(按内部边界按鼠标按钮释放的顺序离开:0),在orangeBorder内部按鼠标左键,在窗口外部移动(快速)执行离开处理程序(1-4)。在窗口外释放鼠标按钮,移回goldTextBox(5),在文本框中按下鼠标左键,在窗口外(快速或慢速)再次执行正确的处理程序(6-9)

Xaml(示例):


代码隐藏(仅用于调试目的):

public分部类MouseLeaveControlWindow:Window
{
公共MouseLeaveControlWindow()
{
初始化组件();
}
私有整数i=0;
MouseLeave上的私有void(对象发送者,MouseEventArgs e)
{
FrameworkElement fe=(FrameworkElement)发送方;
如果(e.LeftButton==鼠标按钮状态。按下)
{
System.Diagnostics.Debug.WriteLine(string.Format(“{0}:Left{1}.”,i,fe.Name));i++;
}
其他的
{
System.Diagnostics.Debug.WriteLine(string.Format(“{0}:左{1}(已发布)。”,i,fe.Name));i++;
}
}
}
监控行为:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Interop;
using System.ComponentModel;
using System.Windows.Media;
using WpfApplication1.Helpers;

namespace WpfApplication1.Behavior
{
    public class MonitorMouseLeaveBehavior : Behavior<FrameworkElement>
    {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetCursorPos(ref Win32Point pt);

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

        [DllImport("user32.dll")]
        public static extern short GetAsyncKeyState(UInt16 virtualKeyCode);

        private enum VK
        {
            LBUTTON = 0x01
        }

        private bool _tracking;
        private const int _interval = 1;
        private Timer _checkPosTimer = new Timer(_interval);
        private Dictionary<FrameworkElement, RoutedEventHandlerInfo[]> _leaveHandlersForElement = new Dictionary<FrameworkElement, RoutedEventHandlerInfo[]>();
        private Window _window;
        private Dictionary<FrameworkElement, Rect> _boundsByElement = new Dictionary<FrameworkElement, Rect>();
        private Dictionary<FrameworkElement, bool> _wasInside = new Dictionary<FrameworkElement, bool>();
        private List<FrameworkElement> _elements = new List<FrameworkElement>();


        /// <summary>
        /// If true, all subcontrols are monitored for the mouseleave event when left mousebutton is down.
        /// True by default.
        /// </summary>
        public bool MonitorSubControls { get { return (bool)GetValue(MonitorSubControlsProperty); } set { SetValue(MonitorSubControlsProperty, value); } }
        public static readonly DependencyProperty MonitorSubControlsProperty = DependencyProperty.Register("MonitorSubControls", typeof(bool), typeof(MonitorMouseLeaveBehavior), new PropertyMetadata(true, OnMonitorSubControlsChanged));

        private static void OnMonitorSubControlsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MonitorMouseLeaveBehavior beh = (MonitorMouseLeaveBehavior)d;
            beh.AddOrRemoveLogicalChildren((bool)e.NewValue);
        }

        /// <summary>
        /// Initial actions
        /// </summary>
        protected override void OnAttached()
        {
            _window = this.AssociatedObject is Window ? (Window)this.AssociatedObject : Window.GetWindow(this.AssociatedObject); // get window
            _window.SourceInitialized += (s, e) =>
            {
                this.AddOrRemoveLogicalChildren(this.MonitorSubControls); // get all monitored elements
                this.AttachHandlers(true); // attach mousedown and sizechanged handlers
                this.GetAllBounds(); // determine bounds of all elements
                _checkPosTimer.Elapsed += (s1, e1) => Dispatcher.BeginInvoke((Action)(() => { CheckPosition(); }));
            };
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            this.AttachHandlers(false);
            base.OnDetaching();
        }

        /// <summary>
        /// Starts or stops monitoring of the AssociatedObject's logical children.
        /// </summary>
        /// <param name="add"></param>
        private void AddOrRemoveLogicalChildren(bool add)
        {
            if (_window != null && _window.IsInitialized)
            {
                AddOrRemoveSizeChangedHandlers(false);
                _elements.Clear();
                if (add)
                    _elements.AddRange(VisualHelper.FindLogicalChildren<FrameworkElement>(this.AssociatedObject));
                _elements.Add(this.AssociatedObject);
                AddOrRemoveSizeChangedHandlers(true);
            }
        }

        /// <summary>
        /// Attaches/detaches size changed handlers to the monitored elements
        /// </summary>
        /// <param name="add"></param>
        private void AddOrRemoveSizeChangedHandlers(bool add)
        {
            foreach (var element in _elements)
            {
                element.SizeChanged -= element_SizeChanged;
                if (add) element.SizeChanged += element_SizeChanged;
            }
        }

        /// <summary>
        /// Adjusts the stored bounds to the changed size
        /// </summary>
        void element_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            FrameworkElement fe = sender as FrameworkElement;
            if (fe != null)
                GetBounds(fe);
        }

        /// <summary>
        /// Attaches/Detaches MouseLeftButtonDown and SizeChanged handlers 
        /// </summary>
        /// <param name="attach">true: attach, false: detach</param>
        private void AttachHandlers(bool attach)
        {
            AddOrRemoveSizeChangedHandlers(attach);

            if (attach)
                _window.PreviewMouseLeftButtonDown += window_PreviewMouseLeftButtonDown;
            else // detach
                _window.PreviewMouseLeftButtonDown -= window_PreviewMouseLeftButtonDown;
        }

        /// <summary>
        /// Gets the bounds for all monitored elements
        /// </summary>
        private void GetAllBounds()
        {
            _boundsByElement.Clear();
            foreach (var element in _elements)
                GetBounds(element);
        }

        /// <summary>
        /// Gets the bounds of the control, which are used to check if the mouse position
        /// is located within. Note that this only covers rectangular control shapes.
        /// </summary>
        private void GetBounds(FrameworkElement element)
        {
            Point p1 = new Point(0, 0);
            Point p2 = new Point(element.ActualWidth, element.ActualHeight);
            p1 = element.TransformToVisual(_window).Transform(p1);
            p2 = element.TransformToVisual(_window).Transform(p2);

            if (element == _window) // window bounds need to account for the border
            {
                var titleHeight = SystemParameters.WindowCaptionHeight + 2 * SystemParameters.ResizeFrameHorizontalBorderHeight; //  not sure about that one
                var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;
                p1.Offset(-verticalBorderWidth, -titleHeight);
                p2.Offset(-verticalBorderWidth, -titleHeight);
            }

            Rect bounds = new Rect(p1, p2);

            if (_boundsByElement.ContainsKey(element))
                _boundsByElement[element] = bounds;
            else
                _boundsByElement.Add(element, bounds);
        }

        /// <summary>
        /// For all monitored elements, detach the MouseLeave event handlers and store them locally,
        /// to be executed manually.
        /// </summary>
        private void RerouteLeaveHandlers()
        {
            foreach (var element in _elements)
            {
                if (!_leaveHandlersForElement.ContainsKey(element))
                {
                    var handlers = ReflectionHelper.GetRoutedEventHandlers(element, UIElement.MouseLeaveEvent);
                    if (handlers != null)
                    {
                        _leaveHandlersForElement.Add(element, handlers);
                        foreach (var handler in handlers)
                            element.MouseLeave -= (MouseEventHandler)handler.Handler; // detach handlers
                    }
                }
            }
        }

        /// <summary>
        /// Reattach all leave handlers that were detached in window_PreviewMouseLeftButtonDown.
        /// </summary>
        private void ReattachLeaveHandlers()
        {
            foreach (var kvp in _leaveHandlersForElement)
            {
                FrameworkElement fe = kvp.Key;
                foreach (var handler in kvp.Value)
                {
                    if (handler.Handler is MouseEventHandler)
                        fe.MouseLeave += (MouseEventHandler)handler.Handler;
                }
            }

            _leaveHandlersForElement.Clear();
        }

        /// <summary>
        /// Checks if the mouse position is inside the bounds of the elements
        /// If there is a transition from inside to outside, the leave event handlers are executed
        /// </summary>
        private void DetermineIsInside()
        {
            Point p = _window.PointFromScreen(GetMousePosition());
            foreach (var element in _elements)
            {
                if (_boundsByElement.ContainsKey(element))
                {
                    bool isInside = _boundsByElement[element].Contains(p);
                    bool wasInside = _wasInside.ContainsKey(element) && _wasInside[element];

                    if (wasInside && !isInside)
                        ExecuteLeaveHandlers(element);

                    if (_wasInside.ContainsKey(element))
                        _wasInside[element] = isInside;
                    else
                        _wasInside.Add(element, isInside);
                }
            }
        }

        /// <summary>
        /// Gets the mouse position relative to the screen
        /// </summary>
        public static Point GetMousePosition()
        {
            Win32Point w32Mouse = new Win32Point();
            GetCursorPos(ref w32Mouse);
            return new Point(w32Mouse.X, w32Mouse.Y);
        }

        /// <summary>
        /// Gets the mouse button state. MouseEventArgs.LeftButton is notoriously unreliable.
        /// </summary>
        private bool IsMouseLeftButtonPressed()
        {
            short leftMouseKeyState = GetAsyncKeyState((ushort)VK.LBUTTON);
            bool ispressed = leftMouseKeyState < 0;

            return ispressed;
        }

        /// <summary>
        /// Executes the leave handlers that were attached to the controls.
        /// They have been detached previously by this behavior (see window_PreviewMouseLeftButtonDown), to prevent double execution.
        /// After mouseup, they are reattached (see CheckPosition)
        /// </summary>
        private void ExecuteLeaveHandlers(FrameworkElement fe)
        {
            MouseDevice mouseDev = InputManager.Current.PrimaryMouseDevice;
            MouseEventArgs mouseEvent = new MouseEventArgs(mouseDev, 0) { RoutedEvent = Control.MouseLeaveEvent };

            if (_leaveHandlersForElement.ContainsKey(fe))
            {
                foreach (var handler in _leaveHandlersForElement[fe])
                {
                    if (handler.Handler is MouseEventHandler)
                        ((MouseEventHandler)handler.Handler).Invoke(fe, mouseEvent);
                }
            }
        }

        /// <summary>
        /// Sets the mouse capture (events outside the window are still directed to it),
        /// and tells the behavior to watch out for a missed leave event
        /// </summary>
        private void window_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("--- left mousebutton down ---"); // todo remove

            this.RerouteLeaveHandlers();
            _tracking = true;
            _checkPosTimer.Start();
        }

        /// <summary>
        /// Uses the _tracking field as well as left mouse button state to determine if either 
        /// leave event handlers should be executed, or monitoring should be stopped.
        /// </summary>
        private void CheckPosition()
        {
            if (_tracking)
            {
                if (IsMouseLeftButtonPressed())
                {
                    this.DetermineIsInside();
                }
                else
                {
                    _wasInside.Clear();
                    _tracking = false;
                    _checkPosTimer.Stop();
                    System.Diagnostics.Debug.WriteLine("--- left mousebutton up ---"); // todo remove

                    // invoking ReattachLeaveHandlers() immediately would rethrow MouseLeave for top grid/window 
                    // if both a) mouse is outside window and b) mouse moves. Wait with reattach until mouse is inside window again and moves.
                    _window.MouseMove += ReattachHandler; 
                }
            }
        }

        /// <summary>
        /// Handles the first _window.MouseMove event after left mouse button was released,
        /// and reattaches the MouseLeaveHandlers. Detaches itself to be executed only once.
        /// </summary>
        private void ReattachHandler(object sender, MouseEventArgs e)
        {
            ReattachLeaveHandlers();
            _window.MouseMove -= ReattachHandler; // only once
        }
    }
}
使用系统;
使用System.Linq;
使用System.Collections.Generic;
运用系统反思;
使用System.Runtime.InteropServices;
使用系统计时器;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
使用System.Windows.Interactive;
使用System.Windows.Interop;
使用系统组件模型;
使用System.Windows.Media;
使用WpfApplication1.Helpers;
命名空间WpfApplication1.Behavior
{
公共类监视行为:行为
{
[DllImport(“user32.dll”)]
[返回:Marshallas(UnmanagedType.Bool)]
内部静态外部bool GetCursorPos(参考Win32Point pt);
[StructLayout(LayoutKind。
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Interop;
using System.ComponentModel;
using System.Windows.Media;
using WpfApplication1.Helpers;

namespace WpfApplication1.Behavior
{
    public class MonitorMouseLeaveBehavior : Behavior<FrameworkElement>
    {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetCursorPos(ref Win32Point pt);

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

        [DllImport("user32.dll")]
        public static extern short GetAsyncKeyState(UInt16 virtualKeyCode);

        private enum VK
        {
            LBUTTON = 0x01
        }

        private bool _tracking;
        private const int _interval = 1;
        private Timer _checkPosTimer = new Timer(_interval);
        private Dictionary<FrameworkElement, RoutedEventHandlerInfo[]> _leaveHandlersForElement = new Dictionary<FrameworkElement, RoutedEventHandlerInfo[]>();
        private Window _window;
        private Dictionary<FrameworkElement, Rect> _boundsByElement = new Dictionary<FrameworkElement, Rect>();
        private Dictionary<FrameworkElement, bool> _wasInside = new Dictionary<FrameworkElement, bool>();
        private List<FrameworkElement> _elements = new List<FrameworkElement>();


        /// <summary>
        /// If true, all subcontrols are monitored for the mouseleave event when left mousebutton is down.
        /// True by default.
        /// </summary>
        public bool MonitorSubControls { get { return (bool)GetValue(MonitorSubControlsProperty); } set { SetValue(MonitorSubControlsProperty, value); } }
        public static readonly DependencyProperty MonitorSubControlsProperty = DependencyProperty.Register("MonitorSubControls", typeof(bool), typeof(MonitorMouseLeaveBehavior), new PropertyMetadata(true, OnMonitorSubControlsChanged));

        private static void OnMonitorSubControlsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MonitorMouseLeaveBehavior beh = (MonitorMouseLeaveBehavior)d;
            beh.AddOrRemoveLogicalChildren((bool)e.NewValue);
        }

        /// <summary>
        /// Initial actions
        /// </summary>
        protected override void OnAttached()
        {
            _window = this.AssociatedObject is Window ? (Window)this.AssociatedObject : Window.GetWindow(this.AssociatedObject); // get window
            _window.SourceInitialized += (s, e) =>
            {
                this.AddOrRemoveLogicalChildren(this.MonitorSubControls); // get all monitored elements
                this.AttachHandlers(true); // attach mousedown and sizechanged handlers
                this.GetAllBounds(); // determine bounds of all elements
                _checkPosTimer.Elapsed += (s1, e1) => Dispatcher.BeginInvoke((Action)(() => { CheckPosition(); }));
            };
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            this.AttachHandlers(false);
            base.OnDetaching();
        }

        /// <summary>
        /// Starts or stops monitoring of the AssociatedObject's logical children.
        /// </summary>
        /// <param name="add"></param>
        private void AddOrRemoveLogicalChildren(bool add)
        {
            if (_window != null && _window.IsInitialized)
            {
                AddOrRemoveSizeChangedHandlers(false);
                _elements.Clear();
                if (add)
                    _elements.AddRange(VisualHelper.FindLogicalChildren<FrameworkElement>(this.AssociatedObject));
                _elements.Add(this.AssociatedObject);
                AddOrRemoveSizeChangedHandlers(true);
            }
        }

        /// <summary>
        /// Attaches/detaches size changed handlers to the monitored elements
        /// </summary>
        /// <param name="add"></param>
        private void AddOrRemoveSizeChangedHandlers(bool add)
        {
            foreach (var element in _elements)
            {
                element.SizeChanged -= element_SizeChanged;
                if (add) element.SizeChanged += element_SizeChanged;
            }
        }

        /// <summary>
        /// Adjusts the stored bounds to the changed size
        /// </summary>
        void element_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            FrameworkElement fe = sender as FrameworkElement;
            if (fe != null)
                GetBounds(fe);
        }

        /// <summary>
        /// Attaches/Detaches MouseLeftButtonDown and SizeChanged handlers 
        /// </summary>
        /// <param name="attach">true: attach, false: detach</param>
        private void AttachHandlers(bool attach)
        {
            AddOrRemoveSizeChangedHandlers(attach);

            if (attach)
                _window.PreviewMouseLeftButtonDown += window_PreviewMouseLeftButtonDown;
            else // detach
                _window.PreviewMouseLeftButtonDown -= window_PreviewMouseLeftButtonDown;
        }

        /// <summary>
        /// Gets the bounds for all monitored elements
        /// </summary>
        private void GetAllBounds()
        {
            _boundsByElement.Clear();
            foreach (var element in _elements)
                GetBounds(element);
        }

        /// <summary>
        /// Gets the bounds of the control, which are used to check if the mouse position
        /// is located within. Note that this only covers rectangular control shapes.
        /// </summary>
        private void GetBounds(FrameworkElement element)
        {
            Point p1 = new Point(0, 0);
            Point p2 = new Point(element.ActualWidth, element.ActualHeight);
            p1 = element.TransformToVisual(_window).Transform(p1);
            p2 = element.TransformToVisual(_window).Transform(p2);

            if (element == _window) // window bounds need to account for the border
            {
                var titleHeight = SystemParameters.WindowCaptionHeight + 2 * SystemParameters.ResizeFrameHorizontalBorderHeight; //  not sure about that one
                var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;
                p1.Offset(-verticalBorderWidth, -titleHeight);
                p2.Offset(-verticalBorderWidth, -titleHeight);
            }

            Rect bounds = new Rect(p1, p2);

            if (_boundsByElement.ContainsKey(element))
                _boundsByElement[element] = bounds;
            else
                _boundsByElement.Add(element, bounds);
        }

        /// <summary>
        /// For all monitored elements, detach the MouseLeave event handlers and store them locally,
        /// to be executed manually.
        /// </summary>
        private void RerouteLeaveHandlers()
        {
            foreach (var element in _elements)
            {
                if (!_leaveHandlersForElement.ContainsKey(element))
                {
                    var handlers = ReflectionHelper.GetRoutedEventHandlers(element, UIElement.MouseLeaveEvent);
                    if (handlers != null)
                    {
                        _leaveHandlersForElement.Add(element, handlers);
                        foreach (var handler in handlers)
                            element.MouseLeave -= (MouseEventHandler)handler.Handler; // detach handlers
                    }
                }
            }
        }

        /// <summary>
        /// Reattach all leave handlers that were detached in window_PreviewMouseLeftButtonDown.
        /// </summary>
        private void ReattachLeaveHandlers()
        {
            foreach (var kvp in _leaveHandlersForElement)
            {
                FrameworkElement fe = kvp.Key;
                foreach (var handler in kvp.Value)
                {
                    if (handler.Handler is MouseEventHandler)
                        fe.MouseLeave += (MouseEventHandler)handler.Handler;
                }
            }

            _leaveHandlersForElement.Clear();
        }

        /// <summary>
        /// Checks if the mouse position is inside the bounds of the elements
        /// If there is a transition from inside to outside, the leave event handlers are executed
        /// </summary>
        private void DetermineIsInside()
        {
            Point p = _window.PointFromScreen(GetMousePosition());
            foreach (var element in _elements)
            {
                if (_boundsByElement.ContainsKey(element))
                {
                    bool isInside = _boundsByElement[element].Contains(p);
                    bool wasInside = _wasInside.ContainsKey(element) && _wasInside[element];

                    if (wasInside && !isInside)
                        ExecuteLeaveHandlers(element);

                    if (_wasInside.ContainsKey(element))
                        _wasInside[element] = isInside;
                    else
                        _wasInside.Add(element, isInside);
                }
            }
        }

        /// <summary>
        /// Gets the mouse position relative to the screen
        /// </summary>
        public static Point GetMousePosition()
        {
            Win32Point w32Mouse = new Win32Point();
            GetCursorPos(ref w32Mouse);
            return new Point(w32Mouse.X, w32Mouse.Y);
        }

        /// <summary>
        /// Gets the mouse button state. MouseEventArgs.LeftButton is notoriously unreliable.
        /// </summary>
        private bool IsMouseLeftButtonPressed()
        {
            short leftMouseKeyState = GetAsyncKeyState((ushort)VK.LBUTTON);
            bool ispressed = leftMouseKeyState < 0;

            return ispressed;
        }

        /// <summary>
        /// Executes the leave handlers that were attached to the controls.
        /// They have been detached previously by this behavior (see window_PreviewMouseLeftButtonDown), to prevent double execution.
        /// After mouseup, they are reattached (see CheckPosition)
        /// </summary>
        private void ExecuteLeaveHandlers(FrameworkElement fe)
        {
            MouseDevice mouseDev = InputManager.Current.PrimaryMouseDevice;
            MouseEventArgs mouseEvent = new MouseEventArgs(mouseDev, 0) { RoutedEvent = Control.MouseLeaveEvent };

            if (_leaveHandlersForElement.ContainsKey(fe))
            {
                foreach (var handler in _leaveHandlersForElement[fe])
                {
                    if (handler.Handler is MouseEventHandler)
                        ((MouseEventHandler)handler.Handler).Invoke(fe, mouseEvent);
                }
            }
        }

        /// <summary>
        /// Sets the mouse capture (events outside the window are still directed to it),
        /// and tells the behavior to watch out for a missed leave event
        /// </summary>
        private void window_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("--- left mousebutton down ---"); // todo remove

            this.RerouteLeaveHandlers();
            _tracking = true;
            _checkPosTimer.Start();
        }

        /// <summary>
        /// Uses the _tracking field as well as left mouse button state to determine if either 
        /// leave event handlers should be executed, or monitoring should be stopped.
        /// </summary>
        private void CheckPosition()
        {
            if (_tracking)
            {
                if (IsMouseLeftButtonPressed())
                {
                    this.DetermineIsInside();
                }
                else
                {
                    _wasInside.Clear();
                    _tracking = false;
                    _checkPosTimer.Stop();
                    System.Diagnostics.Debug.WriteLine("--- left mousebutton up ---"); // todo remove

                    // invoking ReattachLeaveHandlers() immediately would rethrow MouseLeave for top grid/window 
                    // if both a) mouse is outside window and b) mouse moves. Wait with reattach until mouse is inside window again and moves.
                    _window.MouseMove += ReattachHandler; 
                }
            }
        }

        /// <summary>
        /// Handles the first _window.MouseMove event after left mouse button was released,
        /// and reattaches the MouseLeaveHandlers. Detaches itself to be executed only once.
        /// </summary>
        private void ReattachHandler(object sender, MouseEventArgs e)
        {
            ReattachLeaveHandlers();
            _window.MouseMove -= ReattachHandler; // only once
        }
    }
}
public static List<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject
{
    List<T> children = new List<T>();
    foreach (var child in LogicalTreeHelper.GetChildren(obj))
    {
        if (child != null)
        {
            if (child is T)
                children.Add((T)child);

            if (child is DependencyObject)
                children.AddRange(FindLogicalChildren<T>((DependencyObject)child)); // recursive
        }
    }
    return children;
}
/// <summary>
/// Gets the list of routed event handlers subscribed to the specified routed event.
/// </summary>
/// <param name="element">The UI element on which the event is defined.</param>
/// <param name="routedEvent">The routed event for which to retrieve the event handlers.</param>
/// <returns>The list of subscribed routed event handlers.</returns>
public static RoutedEventHandlerInfo[] GetRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
{
    var routedEventHandlers = default(RoutedEventHandlerInfo[]);
    // Get the EventHandlersStore instance which holds event handlers for the specified element.
    // The EventHandlersStore class is declared as internal.
    var eventHandlersStoreProperty = typeof(UIElement).GetProperty("EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
    object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);

    if (eventHandlersStore != null)
    {
        // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
        // for getting an array of the subscribed event handlers.
        var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(eventHandlersStore, new object[] { routedEvent });
    }
    return routedEventHandlers;
}
my:Hooks.EnterCommand="{Binding EnterCommand}"
my:Hooks.LeaveCommand="{Binding LeaveCommand}"
my:Hooks.MouseMoveCommand="{Binding MoveCommand}"
RelayCommand _enterCommand;
public RelayCommand EnterCommand
{
    get
    {
        return _enterCommand ?? (_enterCommand = new RelayCommand(param =>
        {
            var point = (Point)param;
            test1.Content = "Mouse entered";
            // test2.Content = point.ToString();
        },
        param => true));
    }
}
public static class Hooks
{
    private static Dictionary<ContentControl, Action> _hash = new Dictionary<ContentControl, Action>();

    #region MouseMoveCommand

    public static ICommand GetMouseMoveCommand(ContentControl control) { return (ICommand)control.GetValue(MouseMoveCommandProperty); }
    public static void SetMouseMoveCommand(ContentControl control, ICommand value) { control.SetValue(MouseMoveCommandProperty, value); }
    public static readonly DependencyProperty MouseMoveCommandProperty =
        DependencyProperty.RegisterAttached("MouseMoveCommand", typeof(ICommand), typeof(Hooks), new UIPropertyMetadata(null, OnMouseMoveCommandChanged));
    static void OnMouseMoveCommandChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        ContentControl control = depObj as ContentControl;
        if (control != null && e.NewValue is ICommand)
            SetupMouseMove(control);
    }
    static void Instance_MouseMoveLL(object sender, WinHook.MouseLLMessageArgs e)
    {
    }
    static void OnAutoGeneratingColumn(ICommand command, object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (command.CanExecute(e)) command.Execute(e);
    }

    #endregion

    #region EnterCommand

    public static ICommand GetEnterCommand(ContentControl control) { return (ICommand)control.GetValue(EnterCommandProperty); }
    public static void SetEnterCommand(ContentControl control, ICommand value) { control.SetValue(EnterCommandProperty, value); }
    public static readonly DependencyProperty EnterCommandProperty =
        DependencyProperty.RegisterAttached("EnterCommand", typeof(ICommand), typeof(Hooks), new UIPropertyMetadata(null, OnEnterCommandChanged));
    static void OnEnterCommandChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        ContentControl control = depObj as ContentControl;
        if (control != null && e.NewValue is ICommand)
            SetupMouseMove(control);
    }

    #endregion

    #region LeaveCommand

    public static ICommand GetLeaveCommand(ContentControl control) { return (ICommand)control.GetValue(LeaveCommandProperty); }
    public static void SetLeaveCommand(ContentControl control, ICommand value) { control.SetValue(LeaveCommandProperty, value); }
    public static readonly DependencyProperty LeaveCommandProperty =
        DependencyProperty.RegisterAttached("LeaveCommand", typeof(ICommand), typeof(Hooks), new UIPropertyMetadata(null, OnLeaveCommandChanged));
    static void OnLeaveCommandChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        ContentControl control = depObj as ContentControl;
        if (control != null && e.NewValue is ICommand)
            SetupMouseMove(control);
    }

    #endregion

    static void SetupMouseMove(ContentControl control)
    {
        Action onmove;
        if (_hash.TryGetValue(control, out onmove) == false)
        {
            onmove = () =>
            {
                var entered = false;
                var moveCommand = control.GetValue(Hooks.MouseMoveCommandProperty) as ICommand;
                var enterCommand = control.GetValue(Hooks.EnterCommandProperty) as ICommand;
                var leaveCommand = control.GetValue(Hooks.LeaveCommandProperty) as ICommand;

                // hook is invoked on the 'caller thread' (i.e. your GUI one) so it's safe
                // don't forget to unhook and dispose / release it, handle unsubscribe for events
                WinHook.Instance.MouseMoveLL += (s, e) =>
                {
                    Point point = control.PointFromScreen(new Point(e.Message.Pt.X, e.Message.Pt.Y));

                    if (moveCommand != null && moveCommand.CanExecute(point))
                        moveCommand.Execute(point);

                    var newEntered = control.IsMouseInBounds(point); // don't use 'IsMouseOver'
                    if (newEntered != entered)
                    {
                        entered = newEntered;
                        if (entered)
                        {
                            if (enterCommand != null && enterCommand.CanExecute(point))
                                enterCommand.Execute(point);
                        }
                        else
                        {
                            if (leaveCommand != null && leaveCommand.CanExecute(point))
                                leaveCommand.Execute(point);
                        }
                    }
                };
            };
            control.Loaded += (s, e) => onmove();
            _hash[control] = onmove;
        }
    }
    private static bool IsMouseInBounds(this ContentControl control, Point point)
    {
        var client = ((FrameworkElement)control.Content);
        Rect bounds = new Rect(0, 0, client.ActualWidth, client.ActualHeight);
        return bounds.Contains(point);
    }
}
public sealed class WinHook : IDisposable
{
    public static readonly WinHook Instance = new WinHook();

    public const int WH_MOUSE_LL = 14;
    public const uint WM_MOUSEMOVE = 0x0200;

    public delegate void MouseLLMessageHandler(object sender, MouseLLMessageArgs e);
    public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern int GetCurrentThreadId();

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    public static extern bool UnhookWindowsHookEx(int idHook);

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
    public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);

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

    [StructLayout(LayoutKind.Sequential)]
    public class MouseLLHookStruct
    {
        public POINT Pt;
        public uint mouseData;
        public uint flags;
        public uint time;
        public uint dwExtraInfo;
    }

    public class MouseLLMessageArgs : EventArgs
    {
        public bool IsProcessed { get; set; }
        public MouseLLHookStruct Message { get; private set; }
        public MouseLLMessageArgs(MouseLLHookStruct message) { this.Message = message; }
    }

    static IntPtr GetModuleHandle()
    {
        using (Process process = Process.GetCurrentProcess())
        using (ProcessModule module = process.MainModule)
            return GetModuleHandle(module.ModuleName);
    }

    public event MouseLLMessageHandler MouseMoveLL;

    int _hLLMouseHook = 0;
    HookProc LLMouseHook;

    private WinHook()
    {
        IntPtr hModule = GetModuleHandle();
        LLMouseHook = LowLevelMouseProc;
        _hLLMouseHook = SetWindowsHookEx(WH_MOUSE_LL, LLMouseHook, hModule, 0);
        if (_hLLMouseHook == 0) { } // "failed w/ an error code: {0}", new Win32Exception(Marshal.GetLastWin32Error()).Message
    }

    public void Release()
    {
        if (_hLLMouseHook == 0) return;
        int hhook = _hLLMouseHook;
        _hLLMouseHook = 0;
        bool ret = UnhookWindowsHookEx(hhook);
        if (ret == false) { } // "failed w/ an error code: {0}", new Win32Exception(Marshal.GetLastWin32Error()).Message
    }

    public int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && lParam.ToInt32() > 0
            && wParam.ToInt32() == (int)WM_MOUSEMOVE)
        {
            MouseLLHookStruct msg = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
            MouseLLMessageArgs args = new MouseLLMessageArgs(msg);
            if (MouseMoveLL != null)
                MouseMoveLL(this, args);
            if (args.IsProcessed)
                return -1; // return 1;
        }
        return CallNextHookEx(_hLLMouseHook, nCode, wParam, lParam);
    }
    // implement IDisposable properly and call `Release` for unmanaged resources / hook
    public void Dispose() { }
}