Skip to content

Commit c148ea1

Browse files
authored
Merge pull request punker76#444 from dmg-hamann/develop
fix touch support
2 parents 1d7fdd3 + f6fed7e commit c148ea1

File tree

5 files changed

+108
-24
lines changed

5 files changed

+108
-24
lines changed

src/GongSolutions.WPF.DragDrop/DragDrop.Properties.cs

+29
Original file line numberDiff line numberDiff line change
@@ -1660,5 +1660,34 @@ public static void SetDropTargetItemsSorter(DependencyObject element, IDropTarge
16601660
{
16611661
element.SetValue(DropTargetItemsSorterProperty, value);
16621662
}
1663+
1664+
/// <summary>
1665+
/// Gets or sets the mouse move triggered by a timer.
1666+
/// </summary>
1667+
public static readonly DependencyProperty MouseMoveTimerTriggeredProperty
1668+
= DependencyProperty.RegisterAttached("MouseMoveTimerTriggered",
1669+
typeof(bool),
1670+
typeof(DragDrop),
1671+
new PropertyMetadata(false));
1672+
1673+
/// <summary>Helper for getting <see cref="MouseMoveTimerTriggeredProperty"/> from <paramref name="element"/>.</summary>
1674+
/// <param name="element"><see cref="DependencyObject"/> to read <see cref="MouseMoveTimerTriggeredProperty"/> from.</param>
1675+
/// <remarks>Gets the mouse move triggered by a timer.</remarks>
1676+
/// <returns>MouseMoveTimerTriggered property value.</returns>
1677+
[AttachedPropertyBrowsableForType(typeof(UIElement))]
1678+
public static bool GetMouseMoveTimerTriggered(DependencyObject element)
1679+
{
1680+
return (bool)element.GetValue(MouseMoveTimerTriggeredProperty);
1681+
}
1682+
1683+
/// <summary>Helper for setting <see cref="MouseMoveTimerTriggeredProperty"/> on <paramref name="element"/>.</summary>
1684+
/// <param name="element"><see cref="DependencyObject"/> to set <see cref="MouseMoveTimerTriggeredProperty"/> on.</param>
1685+
/// <param name="value">MouseMoveTimerTriggered property value.</param>
1686+
/// <remarks>Sets the mouse move triggered by a timer.</remarks>
1687+
[AttachedPropertyBrowsableForType(typeof(UIElement))]
1688+
public static void SetMouseMoveTimerTriggered(DependencyObject element, bool value)
1689+
{
1690+
element.SetValue(MouseMoveTimerTriggeredProperty, value);
1691+
}
16631692
}
16641693
}

src/GongSolutions.WPF.DragDrop/DragDrop.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -639,11 +639,12 @@ private static void DoDragSourceMove(object sender, Func<IInputElement, Point> g
639639
DragDropPreview?.Move(getPosition(DragDropPreview.PlacementTarget));
640640
}
641641

642-
hookId = MouseHelper.HookMouseMove(point =>
643-
{
644-
DragDropPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropPreview.PlacementTarget, point));
645-
DragDropEffectPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropEffectPreview.PlacementTarget, point));
646-
});
642+
hookId = MouseHelper.HookMouseMove(DragDrop.GetMouseMoveTimerTriggered(dragInfo.VisualSource),
643+
point =>
644+
{
645+
DragDropPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropPreview.PlacementTarget, point));
646+
DragDropEffectPreview?.Move(CursorHelper.GetCurrentCursorPosition(DragDropEffectPreview.PlacementTarget, point));
647+
});
647648

648649
var dragDropHandler = dragInfo.DragDropHandler ?? System.Windows.DragDrop.DoDragDrop;
649650
var dragDropEffects = dragDropHandler(dragInfo.VisualSource, dataObject, dragInfo.Effects);

src/GongSolutions.WPF.DragDrop/Utilities/MouseHelper.cs

+50-10
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,62 @@ internal static class MouseHelper
1111

1212
private const int WH_MOUSE_LL = 14;
1313

14-
private static IntPtr _hookID = IntPtr.Zero;
14+
private static bool _timerTriggered;
1515
private static Action<System.Windows.Point> _mouseMoveHandler;
1616

1717
// wee need to keep the variable to prevent the GarbageCollector to remove the HookCallback
1818
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/68fdc3dc-8d77-48c4-875c-5312baa56aee/how-to-fix-callbackoncollecteddelegate-exception?forum=netfxbcl
1919
private static LowLevelMouseProc _proc = HookCallback;
20+
private static System.Windows.Threading.DispatcherTimer _timer;
2021

21-
internal static IntPtr HookMouseMove(Action<System.Windows.Point> mouseMoveHandler)
22+
internal static IntPtr HookMouseMove(bool timerTriggered, Action<System.Windows.Point> mouseMoveHandler)
2223
{
2324
_mouseMoveHandler = mouseMoveHandler;
25+
_timerTriggered = timerTriggered;
2426

25-
using (var process = Process.GetCurrentProcess())
27+
if (_timerTriggered)
2628
{
27-
using (var module = process.MainModule)
28-
{
29-
return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(module.ModuleName), 0);
30-
}
29+
_timer = new System.Windows.Threading.DispatcherTimer(System.Windows.Threading.DispatcherPriority.Input);
30+
_timer.Tick += (_, _) =>
31+
{
32+
if (TryGetCursorPos(out var lpPoint))
33+
{
34+
_mouseMoveHandler?.Invoke(new System.Windows.Point(lpPoint.x, lpPoint.y));
35+
}
36+
};
37+
_timer.Interval = new TimeSpan(1);
38+
_timer.Start();
39+
40+
return IntPtr.Zero;
3141
}
42+
43+
using var process = Process.GetCurrentProcess();
44+
using var module = process.MainModule;
45+
return module != null ? SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(module.ModuleName), 0) : IntPtr.Zero;
3246
}
3347

3448
internal static void RemoveHook(IntPtr hookId)
3549
{
36-
UnhookWindowsHookEx(hookId);
50+
if (_timerTriggered)
51+
{
52+
_timer.Stop();
53+
}
54+
else
55+
{
56+
UnhookWindowsHookEx(hookId);
57+
}
3758
}
3859

3960
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
4061
{
4162
if (nCode >= 0 && MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam)
4263
{
4364
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
44-
//Debug.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
4565
var mousePosScreen = new System.Windows.Point(hookStruct.pt.x, hookStruct.pt.y);
4666
_mouseMoveHandler?.Invoke(mousePosScreen);
4767
}
4868

49-
return CallNextHookEx(_hookID, nCode, wParam, lParam);
69+
return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
5070
}
5171

5272
private enum MouseMessages
@@ -88,5 +108,25 @@ private struct MSLLHOOKSTRUCT
88108

89109
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
90110
private static extern IntPtr GetModuleHandle(string lpModuleName);
111+
112+
[DllImport("user32.dll", EntryPoint = "GetCursorPos", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
113+
[return: MarshalAs(UnmanagedType.Bool)]
114+
private static extern bool _GetCursorPos(out POINT lpPoint);
115+
116+
private static bool TryGetCursorPos(out POINT pt)
117+
{
118+
var returnValue = _GetCursorPos(out pt);
119+
// Sometimes Win32 will fail this call, such as if you are
120+
// not running in the interactive desktop. For example,
121+
// a secure screen saver may be running.
122+
if (!returnValue)
123+
{
124+
Trace.WriteLine("GetCursorPos failed!");
125+
pt.x = 0;
126+
pt.y = 0;
127+
}
128+
129+
return returnValue;
130+
}
91131
}
92132
}

src/Showcase/Views/ListBoxSamples.xaml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
dd:DragDrop.IsDragSource="True"
4444
dd:DragDrop.IsDropTarget="True"
4545
dd:DragDrop.UseDefaultEffectDataTemplate="True"
46+
dd:DragDrop.MouseMoveTimerTriggered="True"
4647
ItemsSource="{Binding Data.Collection1}" />
4748
<ListBox x:Name="RightBoundListBox"
4849
Grid.Column="1"

src/Showcase/Views/SettingsView.xaml

+22-9
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,45 @@
1111
<StackPanel>
1212
<TextBlock Style="{StaticResource DefaultTextBlockStyle}"
1313
Text="{Binding ElementName=This, Path=Caption, Mode=OneWay}" />
14-
<CheckBox Margin="10 5 5 5"
14+
<CheckBox Margin="10 2 2 2"
1515
Content="IsDragSource"
16+
ToolTip="Sets whether the control can be used as drag source."
1617
IsChecked="{Binding Path=(dd:DragDrop.IsDragSource), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
17-
<CheckBox Margin="10 5 5 5"
18+
<CheckBox Margin="10 2 2 2"
1819
Content="IsDropTarget"
20+
ToolTip="Sets whether the control can be used as drop target."
1921
IsChecked="{Binding Path=(dd:DragDrop.IsDropTarget), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
20-
<CheckBox Margin="10 5 5 5"
22+
<CheckBox Margin="10 2 2 2"
2123
Content="DragDirectlySelectedOnly"
24+
ToolTip="Sets whether the drag action should be started only directly on a selected item or also on the free control space (e.g. in a ListBox)."
2225
IsChecked="{Binding Path=(dd:DragDrop.DragDirectlySelectedOnly), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
23-
<CheckBox Margin="10 5 5 5"
26+
<CheckBox Margin="10 2 2 2"
2427
Content="ShowAlwaysDropTargetAdorner"
28+
ToolTip="Sets whether to show the DropTargetAdorner (DropTargetInsertionAdorner) on an empty target too."
2529
IsChecked="{Binding Path=(dd:DragDrop.ShowAlwaysDropTargetAdorner), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
26-
<CheckBox Margin="10 5 5 5"
30+
<CheckBox Margin="10 2 2 2"
2731
Content="SelectDroppedItems"
32+
ToolTip="Sets whether if the dropped items should be select again (should keep the selection)."
2833
IsChecked="{Binding Path=(dd:DragDrop.SelectDroppedItems), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
29-
<CheckBox Margin="10 5 5 5"
34+
<CheckBox Margin="10 2 2 2"
3035
Content="CanDragWithMouseRightButton"
36+
ToolTip="Sets whether the control can be used as drag source together with the right mouse."
3137
IsChecked="{Binding Path=(dd:DragDrop.CanDragWithMouseRightButton), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
32-
<CheckBox Margin="10 5 5 5"
38+
<CheckBox Margin="10 2 2 2"
3339
Content="UseDefaultDragAdorner"
40+
ToolTip="Sets whether if the default DragAdorner should be use."
3441
IsChecked="{Binding Path=(dd:DragDrop.UseDefaultDragAdorner), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
35-
<CheckBox Margin="10 5 5 5"
42+
<CheckBox Margin="10 2 2 2"
3643
Content="UseVisualSourceItemSizeForDragAdorner"
44+
ToolTip="Use descendant bounds of the VisualSourceItem as MinWidth for the DragAdorner."
3745
IsChecked="{Binding Path=(dd:DragDrop.UseVisualSourceItemSizeForDragAdorner), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
38-
<CheckBox Margin="10 5 5 5"
46+
<CheckBox Margin="10 2 2 2"
3947
Content="UseDefaultEffectDataTemplate"
48+
ToolTip="Sets whether if the default DataTemplate for the effects should be use."
4049
IsChecked="{Binding Path=(dd:DragDrop.UseDefaultEffectDataTemplate), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
50+
<CheckBox Margin="10 2 2 2"
51+
Content="MouseMoveTimerTriggered"
52+
ToolTip="Sets the mouse move triggered by a timer."
53+
IsChecked="{Binding Path=(dd:DragDrop.MouseMoveTimerTriggered), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
4154
</StackPanel>
4255
</UserControl>

0 commit comments

Comments
 (0)