Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TabControl support and some improvements #132

Merged
merged 9 commits into from
Apr 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Examples/DefaultsExample/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void DragOver(IDropInfo dropInfo)
public void Drop(IDropInfo dropInfo)
{
MessageBox.Show("He, now it works :-D");
((TextBox)dropInfo.VisualTarget).Text = (string)dropInfo.Data;
((TextBox)dropInfo.VisualTarget).Text = dropInfo.Data != null ? dropInfo.Data.ToString() : string.Empty;
}
}

Expand Down
5 changes: 4 additions & 1 deletion Examples/DefaultsExample/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@
</CollectionViewSource>
</Window.Resources>

<TabControl TabStripPlacement="Left">
<TabControl TabStripPlacement="Left"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultDragAdorner="True">
<TabItem Header="FlowDocument in ItemTemplate #123">
<Grid>
<Grid.ColumnDefinitions>
Expand Down
46 changes: 40 additions & 6 deletions GongSolutions.Wpf.DragDrop/DefaultDropHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ public virtual void DragOver(IDropInfo dropInfo)
{
if (CanAcceptData(dropInfo)) {
// when source is the same as the target set the move effect otherwise set the copy effect
var moveData = dropInfo.DragInfo.VisualSource == dropInfo.VisualTarget || !dropInfo.KeyStates.HasFlag(dropInfo.DragInfo.DragDropCopyKeyState);
var moveData = dropInfo.DragInfo.VisualSource == dropInfo.VisualTarget
|| !dropInfo.KeyStates.HasFlag(dropInfo.DragInfo.DragDropCopyKeyState)
|| dropInfo.DragInfo.VisualSourceItem is TabItem
|| dropInfo.DragInfo.VisualSourceItem is TreeViewItem
|| dropInfo.DragInfo.VisualSourceItem is MenuItem
|| dropInfo.DragInfo.VisualSourceItem is ListBoxItem;
dropInfo.Effects = moveData ? DragDropEffects.Move : DragDropEffects.Copy;
var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter) && dropInfo.VisualTargetItem is TreeViewItem;
dropInfo.DropTargetAdorner = isTreeViewItem ? DropTargetAdorners.Highlight : DropTargetAdorners.Insert;
Expand All @@ -49,7 +54,12 @@ public virtual void Drop(IDropInfo dropInfo)
var data = ExtractData(dropInfo.Data);

// when source is the same as the target remove the data from source and fix the insertion index
var moveData = dropInfo.DragInfo.VisualSource == dropInfo.VisualTarget || !dropInfo.KeyStates.HasFlag(dropInfo.DragInfo.DragDropCopyKeyState);
var moveData = dropInfo.DragInfo.VisualSource == dropInfo.VisualTarget
|| !dropInfo.KeyStates.HasFlag(dropInfo.DragInfo.DragDropCopyKeyState)
|| dropInfo.DragInfo.VisualSourceItem is TabItem
|| dropInfo.DragInfo.VisualSourceItem is TreeViewItem
|| dropInfo.DragInfo.VisualSourceItem is MenuItem
|| dropInfo.DragInfo.VisualSourceItem is ListBoxItem;
if (moveData)
{
var sourceList = dropInfo.DragInfo.SourceCollection.TryGetList();
Expand All @@ -67,8 +77,11 @@ public virtual void Drop(IDropInfo dropInfo)
}
}

var tabControl = dropInfo.VisualTarget as TabControl;

// check for cloning
var cloneData = dropInfo.Effects.HasFlag(DragDropEffects.Copy) || dropInfo.Effects.HasFlag(DragDropEffects.Link);
var cloneData = dropInfo.Effects.HasFlag(DragDropEffects.Copy)
|| dropInfo.Effects.HasFlag(DragDropEffects.Link);
foreach (var o in data) {
var obj2Insert = o;
if (cloneData) {
Expand All @@ -77,7 +90,26 @@ public virtual void Drop(IDropInfo dropInfo)
obj2Insert = cloneable.Clone();
}
}

destinationList.Insert(insertIndex++, obj2Insert);

if (tabControl != null)
{
// call ApplyTemplate for TabItem in TabControl to avoid this error:
//
// System.Windows.Data Error: 4 : Cannot find source for binding with reference
// 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabControl', AncestorLevel='1''.
// BindingExpression:Path=TabStripPlacement; DataItem=null; target element is 'TabItem' (Name='');
// target property is 'NoTarget' (type 'Object')
var container = tabControl.ItemContainerGenerator.ContainerFromItem(obj2Insert) as TabItem;
if (container != null)
{
container.ApplyTemplate();
}

// for better experience: select the dragged TabItem
tabControl.SetSelectedItem(obj2Insert);
}
}
}

Expand Down Expand Up @@ -105,9 +137,11 @@ public static bool CanAcceptData(IDropInfo dropInfo)
if (dropInfo.DragInfo.SourceCollection == dropInfo.TargetCollection) {
var targetList = dropInfo.TargetCollection.TryGetList();
return targetList != null;
} else if (dropInfo.DragInfo.SourceCollection is ItemCollection) {
return false;
} else if (dropInfo.TargetCollection == null) {
}
// else if (dropInfo.DragInfo.SourceCollection is ItemCollection) {
// return false;
// }
else if (dropInfo.TargetCollection == null) {
return false;
} else {
if (TestCompatibleTypes(dropInfo.TargetCollection, dropInfo.Data)) {
Expand Down
58 changes: 46 additions & 12 deletions GongSolutions.Wpf.DragDrop/DragDrop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,18 @@ private static void IsDropTargetChanged(DependencyObject d, DependencyPropertyCh
uiElement.AllowDrop = true;

if (uiElement is ItemsControl) {
// use normal events for ItemsControls
uiElement.DragEnter += DropTarget_PreviewDragEnter;
uiElement.DragLeave += DropTarget_PreviewDragLeave;
uiElement.DragOver += DropTarget_PreviewDragOver;
uiElement.Drop += DropTarget_PreviewDrop;
uiElement.GiveFeedback += DropTarget_GiveFeedback;
((ItemsControl)uiElement).Loaded += (sender, args) => {
if (uiElement is TabControl) {
var tabPanel = ((TabControl)uiElement).GetVisualDescendent<TabPanel>();
//uiElement = tabPanel ?? uiElement;
}
// use normal events for ItemsControls
uiElement.DragEnter += DropTarget_PreviewDragEnter;
uiElement.DragLeave += DropTarget_PreviewDragLeave;
uiElement.DragOver += DropTarget_PreviewDragOver;
uiElement.Drop += DropTarget_PreviewDrop;
uiElement.GiveFeedback += DropTarget_GiveFeedback;
};
} else {
// issue #85: try using preview events for all other elements than ItemsControls
uiElement.PreviewDragEnter += DropTarget_PreviewDragEnter;
Expand All @@ -402,6 +408,10 @@ private static void IsDropTargetChanged(DependencyObject d, DependencyPropertyCh
uiElement.AllowDrop = false;

if (uiElement is ItemsControl) {
if (uiElement is TabControl) {
var tabPanel = ((TabControl)uiElement).GetVisualDescendent<TabPanel>();
//uiElement = tabPanel ?? uiElement;
}
uiElement.DragEnter -= DropTarget_PreviewDragEnter;
uiElement.DragLeave -= DropTarget_PreviewDragLeave;
uiElement.DragOver -= DropTarget_PreviewDragOver;
Expand Down Expand Up @@ -617,10 +627,25 @@ private static DataTemplate GetEffectAdornerTemplate(UIElement target, DragDropE
}
}

private static void Scroll(DependencyObject o, DragEventArgs e)
private static void Scroll(DependencyObject visualTarget, DragEventArgs e)
{
var scrollViewer = o.GetVisualDescendent<ScrollViewer>();
ScrollViewer scrollViewer = null;

if (visualTarget is TabControl)
{
var tabPanel = visualTarget.GetVisualDescendent<TabPanel>();
if (tabPanel != null)
{
scrollViewer = tabPanel.GetVisualAncestor<ScrollViewer>();
if (scrollViewer == null)
{
return;
}
}
}

scrollViewer = scrollViewer ?? visualTarget.GetVisualDescendent<ScrollViewer>();

if (scrollViewer != null) {
var position = e.GetPosition(scrollViewer);
var scrollMargin = Math.Min(scrollViewer.FontSize * 2, scrollViewer.ActualHeight / 2);
Expand Down Expand Up @@ -687,6 +712,7 @@ private static void DragSource_PreviewMouseLeftButtonDown(object sender, MouseBu
|| (sender as UIElement).IsDragSourceIgnored()
|| (e.Source as UIElement).IsDragSourceIgnored()
|| (e.OriginalSource as UIElement).IsDragSourceIgnored()
|| (sender is TabControl) && !HitTestUtilities.HitTest4Type<TabPanel>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<RangeBase>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<ButtonBase>(sender, elementPosition)
|| HitTestUtilities.HitTest4Type<TextBoxBase>(sender, elementPosition)
Expand Down Expand Up @@ -723,11 +749,18 @@ private static void DragSource_PreviewMouseLeftButtonDown(object sender, MouseBu

private static void DragSource_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var elementPosition = e.GetPosition((IInputElement)sender);
if ((sender is TabControl) && !HitTestUtilities.HitTest4Type<TabPanel>(sender, elementPosition)) {
m_DragInfo = null;
m_ClickSupressItem = null;
return;
}

// If we prevented the control's default selection handling in DragSource_PreviewMouseLeftButtonDown
// by setting 'e.Handled = true' and a drag was not initiated, manually set the selection here.
var itemsControl = sender as ItemsControl;

if (itemsControl != null && m_DragInfo != null && m_ClickSupressItem == m_DragInfo.SourceItem) {
if (itemsControl != null && m_DragInfo != null && m_ClickSupressItem != null && m_ClickSupressItem == m_DragInfo.SourceItem) {
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0) {
itemsControl.SetItemSelected(m_DragInfo.SourceItem, false);
} else if ((Keyboard.Modifiers & ModifierKeys.Shift) == 0) {
Expand Down Expand Up @@ -868,8 +901,9 @@ private static void DropTarget_PreviewDragOver(object sender, DragEventArgs e)
// ItemsPresenter provided by the style, try getting hold of a
// ScrollContentPresenter and using that.
var adornedElement =
(UIElement)itemsControl.GetVisualDescendent<ItemsPresenter>() ??
(UIElement)itemsControl.GetVisualDescendent<ScrollContentPresenter>();
itemsControl is TabControl
? itemsControl.GetVisualDescendent<TabPanel>()
: (itemsControl.GetVisualDescendent<ItemsPresenter>() ?? itemsControl.GetVisualDescendent<ScrollContentPresenter>() as UIElement);

if (adornedElement != null) {
if (dropInfo.DropTargetAdorner == null) {
Expand Down Expand Up @@ -905,7 +939,7 @@ private static void DropTarget_PreviewDragOver(object sender, DragEventArgs e)
e.Effects = DragDropEffects.None;
}

Scroll((DependencyObject)dropInfo.VisualTarget, e);
Scroll(dropInfo.VisualTarget, e);
}

private static void DropTarget_PreviewDrop(object sender, DragEventArgs e)
Expand Down
7 changes: 7 additions & 0 deletions GongSolutions.Wpf.DragDrop/DropInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using GongSolutions.Wpf.DragDrop.Utilities;
using System.Windows.Data;

Expand Down Expand Up @@ -58,6 +59,12 @@ public DropInfo(object sender, DragEventArgs e, DragInfo dragInfo)
// visual target can be null, so give us a point...
this.DropPosition = this.VisualTarget != null ? e.GetPosition(this.VisualTarget) : new Point();

if (this.VisualTarget is TabControl) {
if (!HitTestUtilities.HitTest4Type<TabPanel>(this.VisualTarget, this.DropPosition)) {
return;
}
}

if (this.VisualTarget is ItemsControl) {
var itemsControl = (ItemsControl)this.VisualTarget;
item = itemsControl.GetItemContainerAt(this.DropPosition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>gong-wpf-dragdrop</id>
<version>1.0.0-ALPHA006</version>
<version>1.0.0-ALPHA008</version>
<title>gong-wpf-dragdrop</title>
<authors>Jan Karger (punker76), Steven Kirk, mitchell.jon</authors>
<owners>Jan Karger (punker76)</owners>
Expand Down
2 changes: 1 addition & 1 deletion GongSolutions.Wpf.DragDrop/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyProduct("GongSolutions.WPF.DragDrop 1.0.0-ALPHA006")]
[assembly: AssemblyProduct("GongSolutions.WPF.DragDrop 1.0.0-ALPHA008")]
52 changes: 36 additions & 16 deletions GongSolutions.Wpf.DragDrop/Utilities/ItemsControlExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ public static Type GetItemContainerType(this ItemsControl itemsControl, out bool
// determines if the itemsControl is not a ListView, ListBox or TreeView
isItemContainer = false;

if (typeof(TabControl).IsAssignableFrom(itemsControl.GetType())) {
return typeof(TabItem);
}

if (typeof(DataGrid).IsAssignableFrom(itemsControl.GetType())) {
return typeof(DataGridRow);
}
Expand Down Expand Up @@ -172,17 +176,19 @@ public static Type GetItemContainerType(this ItemsControl itemsControl, out bool
var itemsPresenters = itemsControl.GetVisualDescendents<ItemsPresenter>();

foreach (var itemsPresenter in itemsPresenters) {
var panel = VisualTreeHelper.GetChild(itemsPresenter, 0);
var itemContainer = VisualTreeHelper.GetChildrenCount(panel) > 0
? VisualTreeHelper.GetChild(panel, 0)
: null;

// Ensure that this actually *is* an item container by checking it with
// ItemContainerGenerator.
if (itemContainer != null &&
itemsControl.ItemContainerGenerator.IndexFromContainer(itemContainer) != -1) {
isItemContainer = true;
return itemContainer.GetType();
if (VisualTreeHelper.GetChildrenCount(itemsPresenter) > 0) {
var panel = VisualTreeHelper.GetChild(itemsPresenter, 0);
var itemContainer = VisualTreeHelper.GetChildrenCount(panel) > 0
? VisualTreeHelper.GetChild(panel, 0)
: null;

// Ensure that this actually *is* an item container by checking it with
// ItemContainerGenerator.
if (itemContainer != null &&
itemsControl.ItemContainerGenerator.IndexFromContainer(itemContainer) != -1) {
isItemContainer = true;
return itemContainer.GetType();
}
}
}
}
Expand All @@ -192,9 +198,16 @@ public static Type GetItemContainerType(this ItemsControl itemsControl, out bool

public static Orientation GetItemsPanelOrientation(this ItemsControl itemsControl)
{
var itemsPresenter = itemsControl.GetVisualDescendent<ItemsPresenter>();

if (itemsPresenter != null) {
if (itemsControl is TabControl)
{
//HitTestUtilities.HitTest4Type<TabPanel>(sender, elementPosition)
//var tabPanel = itemsControl.GetVisualDescendent<TabPanel>();
var tabControl = (TabControl)itemsControl;
return tabControl.TabStripPlacement == Dock.Left || tabControl.TabStripPlacement == Dock.Right ? Orientation.Vertical : Orientation.Horizontal;
}

var itemsPresenter = itemsControl.GetVisualDescendent<ItemsPresenter>() ?? itemsControl.GetVisualDescendent<ScrollContentPresenter>() as UIElement;
if (itemsPresenter != null && VisualTreeHelper.GetChildrenCount(itemsPresenter) > 0) {
var itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0);
var orientationProperty = itemsPanel.GetType().GetProperty("Orientation", typeof(Orientation));

Expand All @@ -211,7 +224,7 @@ public static FlowDirection GetItemsPanelFlowDirection(this ItemsControl itemsCo
{
var itemsPresenter = itemsControl.GetVisualDescendent<ItemsPresenter>();

if (itemsPresenter != null) {
if (itemsPresenter != null && VisualTreeHelper.GetChildrenCount(itemsPresenter) > 0) {
var itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0);
var flowDirectionProperty = itemsPanel.GetType().GetProperty("FlowDirection", typeof(FlowDirection));

Expand All @@ -236,7 +249,8 @@ public static void SetSelectedItem(this ItemsControl itemsControl, object item)
((ListBox)itemsControl).SelectionMode = SelectionMode.Single;
((ListBox)itemsControl).SelectedItem = null;
((ListBox)itemsControl).SelectedItem = item;
} finally {
}
finally {
((ListBox)itemsControl).SelectionMode = selectionMode;
}
} else if (itemsControl is TreeView) {
Expand Down Expand Up @@ -329,6 +343,12 @@ public static void SetItemSelected(this ItemsControl itemsControl, object item,
} else {
listBox.SelectedItems.Remove(item);
}
} else {
if (value) {
itemsControl.SetSelectedItem(item);
} else {
itemsControl.SetSelectedItem(null);
}
}
}

Expand Down