From 7c5f6fe982392359b624d2e0115e512f3593193d Mon Sep 17 00:00:00 2001 From: Marco Hamann Date: Thu, 9 Jun 2022 15:00:50 +0200 Subject: [PATCH] add MouseMoveTimerTriggered to fix lagging touch drags --- .../DragDrop.Properties.cs | 29 ++++++++++++++ src/GongSolutions.WPF.DragDrop/DragDrop.cs | 4 +- .../Utilities/MouseHelper.cs | 40 ++++++++++++++++--- src/Showcase/Views/ListBoxSamples.xaml | 2 + 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/GongSolutions.WPF.DragDrop/DragDrop.Properties.cs b/src/GongSolutions.WPF.DragDrop/DragDrop.Properties.cs index 04ade227..eab9931b 100644 --- a/src/GongSolutions.WPF.DragDrop/DragDrop.Properties.cs +++ b/src/GongSolutions.WPF.DragDrop/DragDrop.Properties.cs @@ -1660,5 +1660,34 @@ public static void SetDropTargetItemsSorter(DependencyObject element, IDropTarge { element.SetValue(DropTargetItemsSorterProperty, value); } + + /// + /// Gets or sets the mouse move triggerd by timer + /// + public static readonly DependencyProperty MouseMoveTimerTriggeredProperty + = DependencyProperty.RegisterAttached("MouseMoveTimerTriggered", + typeof(bool), + typeof(DragDrop), + new PropertyMetadata(false)); + + /// Helper for getting from . + /// to read from. + /// Gets the mouse move triggerd by timer. + /// MouseMoveTimerTriggeredProperty property value. + [AttachedPropertyBrowsableForType(typeof(UIElement))] + public static bool GetMouseMoveTimerTriggered(DependencyObject element) + { + return (bool)element.GetValue(MouseMoveTimerTriggeredProperty); + } + + /// Helper for setting on . + /// to set on. + /// SetMouseMoveTimerTriggered property value. + /// >Gets the mouse move triggerd by timer. + [AttachedPropertyBrowsableForType(typeof(UIElement))] + public static void SetMouseMoveTimerTriggered(DependencyObject element, bool value) + { + element.SetValue(MouseMoveTimerTriggeredProperty, value); + } } } \ No newline at end of file diff --git a/src/GongSolutions.WPF.DragDrop/DragDrop.cs b/src/GongSolutions.WPF.DragDrop/DragDrop.cs index 3eab35ff..4d3629d8 100644 --- a/src/GongSolutions.WPF.DragDrop/DragDrop.cs +++ b/src/GongSolutions.WPF.DragDrop/DragDrop.cs @@ -639,8 +639,8 @@ private static void DoDragSourceMove(object sender, Func g DragDropPreview?.Move(getPosition(DragDropPreview.PlacementTarget)); } - hookId = MouseHelper.HookMouseMove(point => - { + hookId = MouseHelper.HookMouseMove(DragDrop.GetMouseMoveTimerTriggered(dragInfo.VisualSource), + point => { DragDropPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropPreview.PlacementTarget, point)); DragDropEffectPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropEffectPreview.PlacementTarget, point)); }); diff --git a/src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs b/src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs index b1b35357..97573c61 100644 --- a/src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs +++ b/src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs @@ -11,29 +11,56 @@ internal static class MouseHelper private const int WH_MOUSE_LL = 14; + private static bool _TimerTriggerd; private static IntPtr _hookID = IntPtr.Zero; private static Action _mouseMoveHandler; // wee need to keep the variable to prevent the GarbageCollector to remove the HookCallback // https://social.msdn.microsoft.com/Forums/vstudio/en-US/68fdc3dc-8d77-48c4-875c-5312baa56aee/how-to-fix-callbackoncollecteddelegate-exception?forum=netfxbcl private static LowLevelMouseProc _proc = HookCallback; + private static System.Windows.Threading.DispatcherTimer _timer; - internal static IntPtr HookMouseMove(Action mouseMoveHandler) + internal static IntPtr HookMouseMove(bool TimerTriggerd, Action mouseMoveHandler) { _mouseMoveHandler = mouseMoveHandler; + _TimerTriggerd = TimerTriggerd; - using (var process = Process.GetCurrentProcess()) + if (_TimerTriggerd) { - using (var module = process.MainModule) + _timer = new System.Windows.Threading.DispatcherTimer(System.Windows.Threading.DispatcherPriority.Input); + _timer.Tick += (sender, args) => { - return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(module.ModuleName), 0); + POINT lpPoint; + if (GetCursorPos(out lpPoint)) + _mouseMoveHandler?.Invoke(new System.Windows.Point(lpPoint.x, lpPoint.y)); + }; + _timer.Interval = new TimeSpan(1); + _timer.Start(); + + return IntPtr.Zero; + } + else + { + using (var process = Process.GetCurrentProcess()) + { + using (var module = process.MainModule) + { + return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(module.ModuleName), 0); + } } } } internal static void RemoveHook(IntPtr hookId) { - UnhookWindowsHookEx(hookId); + if (_TimerTriggerd) + { + _timer.Stop(); + } + else + { + UnhookWindowsHookEx(hookId); + } } private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) @@ -88,5 +115,8 @@ private struct MSLLHOOKSTRUCT [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern bool GetCursorPos(out POINT lpPoint); } } \ No newline at end of file diff --git a/src/Showcase/Views/ListBoxSamples.xaml b/src/Showcase/Views/ListBoxSamples.xaml index 530b9a42..7a450501 100644 --- a/src/Showcase/Views/ListBoxSamples.xaml +++ b/src/Showcase/Views/ListBoxSamples.xaml @@ -43,6 +43,7 @@ dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDropTarget="True" dd:DragDrop.UseDefaultEffectDataTemplate="True" + dd:DragDrop.MouseMoveTimerTriggered="True" ItemsSource="{Binding Data.Collection1}" />