Skip to content

Commit

Permalink
fix issue #84
Browse files Browse the repository at this point in the history
- it's now possible to select combox and items, and use the srollbar and
mousewheel
- introduce CanStartDrag method for IDragSource to handle starting
drag&drop
  • Loading branch information
punker76 committed Feb 13, 2014
1 parent 7c892ae commit 7ff929b
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 34 deletions.
31 changes: 31 additions & 0 deletions Examples/DefaultsExample/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Windows.Data;
using System.Windows.Controls;
using System.Collections;
using GongSolutions.Wpf.DragDrop.Utilities;
using DragDrop = GongSolutions.Wpf.DragDrop.DragDrop;

namespace DefaultsExample
Expand All @@ -28,6 +29,34 @@ public void Drop(IDropInfo dropInfo)
}
}

public class CustomDragHandlerForIssue84 : IDragSource
{
public virtual void StartDrag(IDragInfo dragInfo)
{
// nothing special here, use the default way
DragDrop.DefaultDragHandler.StartDrag(dragInfo);
}

public bool CanStartDrag(IDragInfo dragInfo)
{
// so here is the magic
if (dragInfo != null) {
if ((dragInfo.SourceIndex % 2) == 0) {
return false;
}
}
return true;
}

public virtual void Dropped(IDropInfo dropInfo)
{
}

public virtual void DragCancelled()
{
}
}

internal class Data : IDropTarget
{
public Data()
Expand All @@ -39,6 +68,7 @@ public Data()
this.CustomCollection2 = new ObservableCollection<CustomDataModel>();

this.CustomDropHandler = new CustomDropHandlerForIssue85();
this.CustomDragHandler = new CustomDragHandlerForIssue84();

for (var n = 0; n < 100; ++n) {
this.Collection1.Add("Item " + n);
Expand Down Expand Up @@ -76,6 +106,7 @@ public Data()
public ObservableCollection<TreeNode> TreeCollection { get; private set; }

public CustomDropHandlerForIssue85 CustomDropHandler { get; private set; }
public CustomDragHandlerForIssue84 CustomDragHandler { get; private set; }

//
// The drop handler is only used for the grouping example.
Expand Down
42 changes: 42 additions & 0 deletions Examples/DefaultsExample/Window(NET4).xaml
Original file line number Diff line number Diff line change
Expand Up @@ -874,5 +874,47 @@
dd:DragDrop.DropHandler="{Binding CustomDropHandler}" />
</Grid>
</TabItem>

<TabItem Header="Issue #84">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<ListBox Grid.Column="0"
ItemsSource="{Binding Collection1}"
SelectionMode="Extended"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.DragHandler="{Binding CustomDragHandler}"
dd:DragDrop.IsDropTarget="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Margin="2"
Text="{Binding Mode=OneWay}"></TextBlock>
<TextBox Grid.Column="1"
Margin="2"
Text="{Binding Mode=OneWay}"></TextBox>
<ComboBox Grid.Column="2"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.Collection1, Mode=OneWay}"
Margin="2"
Width="80"></ComboBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Column="1"
ItemsSource="{Binding Collection2}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True" />
</Grid>
</TabItem>
</TabControl>
</Window>
5 changes: 5 additions & 0 deletions GongSolutions.Wpf.DragDrop/DefaultDragHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public virtual void StartDrag(IDragInfo dragInfo)
DragDropEffects.None;
}

public bool CanStartDrag(IDragInfo dragInfo)
{
return true;
}

public virtual void Dropped(IDropInfo dropInfo)
{
}
Expand Down
77 changes: 44 additions & 33 deletions GongSolutions.Wpf.DragDrop/DragDrop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,24 +592,43 @@ private static void Scroll(DependencyObject o, DragEventArgs e)
}
}

private static IDragSource TryGetDragHandler(DragInfo dragInfo, UIElement sender)
{
IDragSource dragHandler = null;
if (dragInfo != null && dragInfo.VisualSource != null) {
dragHandler = GetDragHandler(m_DragInfo.VisualSource);
}
if (dragHandler == null && sender != null) {
dragHandler = GetDragHandler(sender);
}
return dragHandler ?? DefaultDragHandler;
}

private static void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Ignore the click if clickCount != 1 or the user has clicked on a scrollbar.
var elementPosition = e.GetPosition((IInputElement)sender);
if (e.ClickCount != 1
|| HitTestUtilities.HitTest4Type<ScrollBar>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<RangeBase>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<TextBoxBase>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<PasswordBox>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<Slider>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<ComboBox>(sender, elementPosition)
|| HitTestUtilities.HitTest4GridViewColumnHeader(sender, elementPosition)
|| HitTestUtilities.HitTest4DataGridTypes(sender, elementPosition)
|| HitTestUtilities.IsNotPartOfSender(sender, e)
|| GetDragSourceIgnore((UIElement)sender)) {
m_DragInfo = null;
return;
}

m_DragInfo = new DragInfo(sender, e);

var dragHandler = TryGetDragHandler(m_DragInfo, sender as UIElement);
if (!dragHandler.CanStartDrag(m_DragInfo)) {
m_DragInfo = null;
return;
}

// If the sender is a list box that allows multiple selections, ensure that clicking on an
// already selected item does not change the selection, otherwise dragging multiple items
// is made impossible.
Expand Down Expand Up @@ -646,18 +665,6 @@ private static void DragSource_PreviewMouseLeftButtonUp(object sender, MouseButt
m_ClickSupressItem = null;
}

private static IDragSource TryGetDragHandler(DragInfo dragInfo, UIElement sender)
{
IDragSource dragHandler = null;
if (dragInfo != null && dragInfo.VisualSource != null) {
dragHandler = GetDragHandler(m_DragInfo.VisualSource);
}
if (dragHandler == null && sender != null) {
dragHandler = GetDragHandler(sender);
}
return dragHandler ?? DefaultDragHandler;
}

private static void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (m_DragInfo != null && !m_DragInProgress) {
Expand All @@ -667,26 +674,30 @@ private static void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
if (Math.Abs(position.X - dragStart.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(position.Y - dragStart.Y) > SystemParameters.MinimumVerticalDragDistance) {
var dragHandler = TryGetDragHandler(m_DragInfo, sender as UIElement);
dragHandler.StartDrag(m_DragInfo);

if (m_DragInfo.Effects != DragDropEffects.None && m_DragInfo.Data != null) {
var data = m_DragInfo.DataObject;

if (data == null) {
data = new DataObject(DataFormat.Name, m_DragInfo.Data);
} else {
data.SetData(DataFormat.Name, m_DragInfo.Data);
}

try {
m_DragInProgress = true;
var result = System.Windows.DragDrop.DoDragDrop(m_DragInfo.VisualSource, data, m_DragInfo.Effects);
if (result == DragDropEffects.None) dragHandler.DragCancelled();
} finally {
m_DragInProgress = false;
if (dragHandler.CanStartDrag(m_DragInfo)) {
dragHandler.StartDrag(m_DragInfo);

if (m_DragInfo.Effects != DragDropEffects.None && m_DragInfo.Data != null) {
var data = m_DragInfo.DataObject;

if (data == null) {
data = new DataObject(DataFormat.Name, m_DragInfo.Data);
} else {
data.SetData(DataFormat.Name, m_DragInfo.Data);
}

try {
m_DragInProgress = true;
var result = System.Windows.DragDrop.DoDragDrop(m_DragInfo.VisualSource, data, m_DragInfo.Effects);
if (result == DragDropEffects.None)
dragHandler.DragCancelled();
}
finally {
m_DragInProgress = false;
}

m_DragInfo = null;
}

m_DragInfo = null;
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions GongSolutions.Wpf.DragDrop/IDragSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public interface IDragSource
/// </remarks>
void StartDrag(IDragInfo dragInfo);

/// <summary>
/// With this action it's possible to check if the drga&drop operation is allowed to start
/// e.g. check for a UIElement inside a list view item, that should not start a drag&drop operation
/// </summary>
bool CanStartDrag(IDragInfo dragInfo);

/// <summary>
/// Notifies the drag handler that a drop has occurred.
/// </summary>
Expand Down
29 changes: 29 additions & 0 deletions GongSolutions.Wpf.DragDrop/Utilities/HitTestUtilities.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

#if NET35
Expand Down Expand Up @@ -73,5 +74,33 @@ public static bool HitTest4DataGridTypesOnDragOver(object sender, Point elementP
}
return false;
}

/// <summary>
/// thx to @osicka from issue #84
///
/// e.g. original source is part of a popup (e.g. ComboBox drop down), the hit test needs to be done on the original source.
/// Because the popup is not attached to the visual tree of the sender.
/// This function test this by looping back from the original source to the sender and if it didn't end up at the sender stopped the drag.
/// </summary>
public static bool IsNotPartOfSender(object sender, MouseButtonEventArgs e)
{
var hit = VisualTreeHelper.HitTest((Visual)e.OriginalSource, e.GetPosition((IInputElement)e.OriginalSource));

if (hit == null) {
return false;
} else {
var depObj = e.OriginalSource as DependencyObject;
if (depObj == null) {
return false;
}
var item = VisualTreeHelper.GetParent(depObj.FindVisualTreeRoot());
//var item = VisualTreeHelper.GetParent(e.OriginalSource as DependencyObject);

while (item != null && item != sender) {
item = VisualTreeHelper.GetParent(item);
}
return item != sender;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace GongSolutions.Wpf.DragDrop.Utilities
{
public static class VisualTreeExtensions
{
private static DependencyObject FindVisualTreeRoot(this DependencyObject d)
internal static DependencyObject FindVisualTreeRoot(this DependencyObject d)
{
var current = d;
var result = d;
Expand Down

0 comments on commit 7ff929b

Please sign in to comment.