添加项目文件。

This commit is contained in:
akwkevin
2021-07-23 09:42:22 +08:00
commit f25a958797
2798 changed files with 352360 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
namespace GongSolutions.Wpf.DragDrop.Utilities
{
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
/// <summary>
/// A helper class for Dpi logicm cause Microsoft hides this with the internal flag.
/// </summary>
public static class DpiHelper
{
private static Matrix _transformToDevice;
private static Matrix _transformToLogical;
public static double DpiX = 0d;
public static double DpiY = 0d;
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static DpiHelper()
{
var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
var pixelsPerInchX = (int)dpiXProperty.GetValue(null, null); //SystemParameters.DpiX;
DpiX = (double)pixelsPerInchX;
var pixelsPerInchY = (int)dpiYProperty.GetValue(null, null); //SystemParameters.Dpi;
DpiY = (double)pixelsPerInchY;
_transformToLogical = Matrix.Identity;
_transformToLogical.Scale(96d / (double)pixelsPerInchX, 96d / (double)pixelsPerInchY);
_transformToDevice = Matrix.Identity;
_transformToDevice.Scale((double)pixelsPerInchX / 96d, (double)pixelsPerInchY / 96d);
}
/// <summary>
/// Convert a point in device independent pixels (1/96") to a point in the system coordinates.
/// </summary>
/// <param name="logicalPoint">A point in the logical coordinate system.</param>
/// <returns>Returns the point converted to the system's coordinates.</returns>
public static Point LogicalPixelsToDevice(Point logicalPoint)
{
return _transformToDevice.Transform(logicalPoint);
}
/// <summary>
/// Convert a point in system coordinates to a point in device independent pixels (1/96").
/// </summary>
/// <param name="devicePoint">A point in the physical coordinate system.</param>
/// <returns>Returns the point converted to the device independent coordinate system.</returns>
public static Point DevicePixelsToLogical(Point devicePoint)
{
return _transformToLogical.Transform(devicePoint);
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static Rect LogicalRectToDevice(Rect logicalRectangle)
{
Point topLeft = LogicalPixelsToDevice(new Point(logicalRectangle.Left, logicalRectangle.Top));
Point bottomRight = LogicalPixelsToDevice(new Point(logicalRectangle.Right, logicalRectangle.Bottom));
return new Rect(topLeft, bottomRight);
}
public static Rect DeviceRectToLogical(Rect deviceRectangle)
{
Point topLeft = DevicePixelsToLogical(new Point(deviceRectangle.Left, deviceRectangle.Top));
Point bottomRight = DevicePixelsToLogical(new Point(deviceRectangle.Right, deviceRectangle.Bottom));
return new Rect(topLeft, bottomRight);
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public static Size LogicalSizeToDevice(Size logicalSize)
{
Point pt = LogicalPixelsToDevice(new Point(logicalSize.Width, logicalSize.Height));
return new Size { Width = pt.X, Height = pt.Y };
}
public static Size DeviceSizeToLogical(Size deviceSize)
{
Point pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height));
return new Size(pt.X, pt.Y);
}
public static Thickness LogicalThicknessToDevice(Thickness logicalThickness)
{
Point topLeft = LogicalPixelsToDevice(new Point(logicalThickness.Left, logicalThickness.Top));
Point bottomRight = LogicalPixelsToDevice(new Point(logicalThickness.Right, logicalThickness.Bottom));
return new Thickness(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y);
}
}
}

View File

@@ -0,0 +1,127 @@
using System.Windows;
using System.Windows.Media;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
using System;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
public static class DragDropExtensions
{
/// <summary>
/// Determines whether the given element is ignored on drag start (<see cref="DragDrop.DragSourceIgnoreProperty"/>).
/// </summary>
/// <param name="element">The given element.</param>
/// <returns>Element is ignored or not.</returns>
public static bool IsDragSourceIgnored(this UIElement element)
{
return element != null && DragDrop.GetDragSourceIgnore(element);
}
/// <summary>
/// Determines whether the given element is ignored on drop action (<see cref="DragDrop.IsDragSourceProperty"/>).
/// </summary>
/// <param name="element">The given element.</param>
/// <returns>Element is ignored or not.</returns>
public static bool IsDragSource(this UIElement element)
{
return element != null && DragDrop.GetIsDragSource(element);
}
/// <summary>
/// Determines whether the given element is ignored on drop action (<see cref="DragDrop.IsDropTargetProperty"/>).
/// </summary>
/// <param name="element">The given element.</param>
/// <returns>Element is ignored or not.</returns>
public static bool IsDropTarget(this UIElement element)
{
return element != null && DragDrop.GetIsDropTarget(element);
}
/// <summary>
/// Gets if drop position is directly over element
/// </summary>
/// <param name="dropPosition">Drop position</param>
/// <param name="element">element to check whether or not the drop position is directly over or not</param>
/// <param name="relativeToElement">element to which the drop position is related</param>
/// <returns>drop position is directly over element or not</returns>
public static bool DirectlyOverElement(this Point dropPosition, UIElement element, UIElement relativeToElement)
{
if (element == null)
return false;
var relativeItemPosition = element.TranslatePoint(new Point(0, 0), relativeToElement);
var relativeDropPosition = new Point(dropPosition.X - relativeItemPosition.X, dropPosition.Y - relativeItemPosition.Y);
return VisualTreeHelper.GetDescendantBounds(element).Contains(relativeDropPosition);
}
/// <summary>
/// Capture screen and create data template containing the captured image
/// </summary>
/// <param name="element">visual source to capture screen of</param>
/// <param name="visualSourceFlowDirection">Flowdirection of visual source</param>
/// <returns></returns>
public static DataTemplate GetCaptureScreenDataTemplate(this UIElement element, FlowDirection visualSourceFlowDirection)
{
DataTemplate template = null;
var bs = CaptureScreen(element, visualSourceFlowDirection);
if (bs != null)
{
var factory = new FrameworkElementFactory(typeof(Image));
factory.SetValue(Image.SourceProperty, bs);
factory.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
factory.SetValue(RenderOptions.BitmapScalingModeProperty, BitmapScalingMode.HighQuality);
factory.SetValue(FrameworkElement.WidthProperty, bs.Width);
factory.SetValue(FrameworkElement.HeightProperty, bs.Height);
factory.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Left);
factory.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Top);
template = new DataTemplate { VisualTree = factory };
}
return template;
}
// Helper to generate the image - I grabbed this off Google
// somewhere. -- Chris Bordeman cbordeman@gmail.com
private static BitmapSource CaptureScreen(Visual target, FlowDirection flowDirection)
{
if (target == null)
{
return null;
}
var dpiX = DpiHelper.DpiX;
var dpiY = DpiHelper.DpiY;
var bounds = VisualTreeHelper.GetDescendantBounds(target);
var dpiBounds = DpiHelper.LogicalRectToDevice(bounds);
var pixelWidth = (int)Math.Ceiling(dpiBounds.Width);
var pixelHeight = (int)Math.Ceiling(dpiBounds.Height);
if (pixelWidth < 0 || pixelHeight < 0)
{
return null;
}
var rtb = new RenderTargetBitmap(pixelWidth, pixelHeight, dpiX, dpiY, PixelFormats.Pbgra32);
var dv = new DrawingVisual();
using (var ctx = dv.RenderOpen())
{
var vb = new VisualBrush(target);
if (flowDirection == FlowDirection.RightToLeft)
{
var transformGroup = new TransformGroup();
transformGroup.Children.Add(new ScaleTransform(-1, 1));
transformGroup.Children.Add(new TranslateTransform(bounds.Size.Width - 1, 0));
ctx.PushTransform(transformGroup);
}
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
}
}

View File

@@ -0,0 +1,135 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
public static class HitTestUtilities
{
public static bool HitTest4Type<T>(object sender, Point elementPosition)
where T : UIElement
{
var uiElement = GetHitTestElement4Type<T>(sender, elementPosition);
return uiElement != null && uiElement.Visibility == Visibility.Visible;
}
private static T GetHitTestElement4Type<T>(object sender, Point elementPosition)
where T : UIElement
{
var visual = sender as Visual;
if (visual == null)
{
return null;
}
var hit = VisualTreeHelper.HitTest(visual, elementPosition);
if (hit == null)
{
return null;
}
var uiElement = hit.VisualHit.GetVisualAncestor<T>();
return uiElement;
}
public static bool HitTest4GridViewColumnHeader(object sender, Point elementPosition)
{
if (sender is ListView)
{
// no drag&drop for column header
var columnHeader = GetHitTestElement4Type<GridViewColumnHeader>(sender, elementPosition);
if (columnHeader != null && (columnHeader.Role == GridViewColumnHeaderRole.Floating || columnHeader.Visibility == Visibility.Visible))
{
return true;
}
}
return false;
}
public static bool HitTest4DataGridTypes(object sender, Point elementPosition)
{
if (sender is DataGrid)
{
// no drag&drop for column header
var columnHeader = GetHitTestElement4Type<DataGridColumnHeader>(sender, elementPosition);
if (columnHeader != null && columnHeader.Visibility == Visibility.Visible)
{
return true;
}
// no drag&drop for row header
var rowHeader = GetHitTestElement4Type<DataGridRowHeader>(sender, elementPosition);
if (rowHeader != null && rowHeader.Visibility == Visibility.Visible)
{
// no drag&drop for row header gripper
var thumb = GetHitTestElement4Type<Thumb>(sender, elementPosition);
if (thumb != null)
{
return true;
}
}
// drag&drop only for data grid row
var dataRow = GetHitTestElement4Type<DataGridRow>(sender, elementPosition);
return dataRow == null || Equals(dataRow.DataContext, CollectionView.NewItemPlaceholder);
}
return false;
}
public static bool HitTest4DataGridTypesOnDragOver(object sender, Point elementPosition)
{
if (sender is DataGrid)
{
// no drag&drop on column header
var columnHeader = GetHitTestElement4Type<DataGridColumnHeader>(sender, elementPosition);
if (columnHeader != null && columnHeader.Visibility == Visibility.Visible)
{
return true;
}
}
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 visual = e.OriginalSource as Visual;
if (visual == null)
{
return false;
}
var hit = VisualTreeHelper.HitTest(visual, e.GetPosition((IInputElement)visual));
if (hit == null)
{
return false;
}
else
{
var depObj = e.OriginalSource as DependencyObject;
if (depObj == null)
{
return false;
}
if (depObj == sender)
{
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;
}
}
}
}

View File

@@ -0,0 +1,622 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Reflection;
using System.Collections;
using System.Windows.Controls.Primitives;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
public static class ItemsControlExtensions
{
public static CollectionViewGroup FindGroup(this ItemsControl itemsControl, Point position)
{
if (itemsControl.Items.Groups == null || itemsControl.Items.Groups.Count == 0)
{
return null;
}
var element = itemsControl.InputHitTest(position) as DependencyObject;
if (element != null)
{
var groupItem = element.GetVisualAncestor<GroupItem>();
// drag after last item - get group of it
if (groupItem == null && itemsControl.Items.Count > 0)
{
var lastItem = itemsControl.ItemContainerGenerator.ContainerFromItem(itemsControl.Items.GetItemAt(itemsControl.Items.Count - 1)) as FrameworkElement;
if (lastItem != null)
{
var itemEndpoint = lastItem.PointToScreen(new Point(lastItem.ActualWidth, lastItem.ActualHeight));
var positionToScreen = itemsControl.PointToScreen(position);
switch (itemsControl.GetItemsPanelOrientation())
{
case Orientation.Horizontal:
// assume LeftToRight
groupItem = itemEndpoint.X <= positionToScreen.X ? lastItem.GetVisualAncestor<GroupItem>() : null;
break;
case Orientation.Vertical:
groupItem = itemEndpoint.Y <= positionToScreen.Y ? lastItem.GetVisualAncestor<GroupItem>() : null;
break;
}
}
}
if (groupItem != null)
{
return groupItem.Content as CollectionViewGroup;
}
}
return null;
}
public static bool CanSelectMultipleItems(this ItemsControl itemsControl)
{
if (itemsControl is MultiSelector multiSelector)
{
// The CanSelectMultipleItems property is protected. Use reflection to
// get its value anyway.
var propertyInfo = multiSelector.GetType().GetProperty("CanSelectMultipleItems", BindingFlags.Instance | BindingFlags.NonPublic);
return propertyInfo != null && (bool)propertyInfo.GetValue(multiSelector, null);
}
else if (itemsControl is ListBox listBox)
{
return listBox.SelectionMode != SelectionMode.Single;
}
else
{
return false;
}
}
public static UIElement GetItemContainer(this ItemsControl itemsControl, DependencyObject child)
{
bool isItemContainer;
var itemType = GetItemContainerType(itemsControl, out isItemContainer);
if (itemType != null)
{
return isItemContainer
? (UIElement)child.GetVisualAncestor(itemType, itemsControl)
: (UIElement)child.GetVisualAncestor(itemType, itemsControl, itemsControl.GetType());
}
return null;
}
public static UIElement GetItemContainerAt(this ItemsControl itemsControl, Point position)
{
var inputElement = itemsControl.InputHitTest(position);
var uiElement = inputElement as UIElement;
if (uiElement != null)
{
return GetItemContainer(itemsControl, uiElement);
}
// ContentElement's such as Run's within TextBlock's could not be used as drop target items, because they are not UIElement's.
var contentElement = inputElement as ContentElement;
if (contentElement != null)
{
return GetItemContainer(itemsControl, contentElement);
}
return null;
}
public static UIElement GetItemContainerAt(this ItemsControl itemsControl, Point position, Orientation searchDirection)
{
bool isItemContainer;
var itemContainerType = GetItemContainerType(itemsControl, out isItemContainer);
Geometry hitTestGeometry;
if (typeof(TreeViewItem).IsAssignableFrom(itemContainerType))
{
hitTestGeometry = new LineGeometry(new Point(0, position.Y), new Point(itemsControl.RenderSize.Width, position.Y));
}
else
{
var geometryGroup = new GeometryGroup();
geometryGroup.Children.Add(new LineGeometry(new Point(0, position.Y), new Point(itemsControl.RenderSize.Width, position.Y)));
geometryGroup.Children.Add(new LineGeometry(new Point(position.X, 0), new Point(position.X, itemsControl.RenderSize.Height)));
hitTestGeometry = geometryGroup;
}
var hits = new HashSet<DependencyObject>();
VisualTreeHelper.HitTest(itemsControl,
obj =>
{
// Viewport3D is not good for us
// Stop on ScrollBar to improve performance (e.g. at DataGrid)
if (obj is Viewport3D || (itemsControl is DataGrid && obj is ScrollBar))
{
return HitTestFilterBehavior.Stop;
}
return HitTestFilterBehavior.Continue;
},
result =>
{
var itemContainer = isItemContainer
? result.VisualHit.GetVisualAncestor(itemContainerType, itemsControl)
: result.VisualHit.GetVisualAncestor(itemContainerType, itemsControl, itemsControl.GetType());
if (itemContainer != null && ((UIElement)itemContainer).IsVisible == true)
{
var tvItem = itemContainer as TreeViewItem;
if (tvItem != null)
{
var tv = tvItem.GetVisualAncestor<TreeView>();
if (tv == itemsControl)
{
hits.Add(itemContainer);
}
}
else
{
if (itemsControl.ItemContainerGenerator.IndexFromContainer(itemContainer) >= 0)
{
hits.Add(itemContainer);
}
}
}
return HitTestResultBehavior.Continue;
},
new GeometryHitTestParameters(hitTestGeometry));
return GetClosest(itemsControl, hits, position, searchDirection);
}
public static Type GetItemContainerType(this ItemsControl itemsControl, out bool isItemContainer)
{
// 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);
}
// There is no safe way to get the item container type for an ItemsControl.
// First hard-code the types for the common ItemsControls.
//if (itemsControl.GetType().IsAssignableFrom(typeof(ListView)))
if (typeof(ListView).IsAssignableFrom(itemsControl.GetType()))
{
return typeof(ListViewItem);
}
//if (itemsControl.GetType().IsAssignableFrom(typeof(ListBox)))
else if (typeof(ListBox).IsAssignableFrom(itemsControl.GetType()))
{
return typeof(ListBoxItem);
}
//else if (itemsControl.GetType().IsAssignableFrom(typeof(TreeView)))
else if (typeof(TreeView).IsAssignableFrom(itemsControl.GetType()))
{
return typeof(TreeViewItem);
}
// Otherwise look for the control's ItemsPresenter, get it's child panel and the first
// child of that *should* be an item container.
//
// If the control currently has no items, we're out of luck.
if (itemsControl.Items.Count > 0)
{
var itemsPresenters = itemsControl.GetVisualDescendents<ItemsPresenter>();
foreach (var itemsPresenter in itemsPresenters)
{
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 &&
!(itemContainer is GroupItem) &&
itemsControl.ItemContainerGenerator.IndexFromContainer(itemContainer) != -1)
{
isItemContainer = true;
return itemContainer.GetType();
}
}
}
}
return null;
}
/// <summary>
/// Gets the Orientation which will be used for the drag drop action.
/// Normally it will be look up to find the correct orientaion of the inner ItemsPanel,
/// but sometimes it's necessary to force the oreintation, if the look up is wrong.
/// If so, the ItemsPanelOrientation value is taken.
/// </summary>
/// <param name="itemsControl">The ItemsControl for the look up.</param>
/// <returns>Orientation for the given ItemsControl.</returns>
public static Orientation GetItemsPanelOrientation(this ItemsControl itemsControl)
{
var itemsPanelOrientation = DragDrop.GetItemsPanelOrientation(itemsControl);
if (itemsPanelOrientation.HasValue)
{
return itemsPanelOrientation.Value;
}
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));
if (orientationProperty != null)
{
return (Orientation)orientationProperty.GetValue(itemsPanel, null);
}
}
// Make a guess!
return Orientation.Vertical;
}
/// <summary>
/// Gets the FlowDirection which will be used for the drag drop action.
/// </summary>
/// <param name="itemsControl">The ItemsControl for the look up.</param>
/// <returns>FlowDirection for the given ItemsControl.</returns>
public static FlowDirection GetItemsPanelFlowDirection(this ItemsControl itemsControl)
{
var itemsPresenter = itemsControl.GetVisualDescendent<ItemsPresenter>() ?? itemsControl.GetVisualDescendent<ScrollContentPresenter>() as UIElement;
if (itemsPresenter != null && VisualTreeHelper.GetChildrenCount(itemsPresenter) > 0)
{
var itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0);
var flowDirectionProperty = itemsPanel.GetType().GetProperty("FlowDirection", typeof(FlowDirection));
if (flowDirectionProperty != null)
{
return (FlowDirection)flowDirectionProperty.GetValue(itemsPanel, null);
}
}
// Make a guess!
return FlowDirection.LeftToRight;
}
/// <summary>
/// Sets the given object as selected item at the ItemsControl.
/// </summary>
/// <param name="itemsControl">The ItemsControl which contains the item.</param>
/// <param name="item">The object which should be selected.</param>
public static void SetSelectedItem(this ItemsControl itemsControl, object item)
{
if (itemsControl is MultiSelector)
{
((MultiSelector)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, null);
((MultiSelector)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, item);
}
else if (itemsControl is ListBox)
{
var selectionMode = ((ListBox)itemsControl).SelectionMode;
try
{
// change SelectionMode for UpdateAnchorAndActionItem
((ListBox)itemsControl).SetCurrentValue(ListBox.SelectionModeProperty, SelectionMode.Single);
((ListBox)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, null);
((ListBox)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, item);
}
finally
{
((ListBox)itemsControl).SetCurrentValue(ListBox.SelectionModeProperty, selectionMode);
}
}
else if (itemsControl is TreeViewItem)
{
// clear old selected item
var treeView = ItemsControl.ItemsControlFromItemContainer((TreeViewItem)itemsControl);
if (treeView != null)
{
var prevSelectedItem = treeView.GetValue(TreeView.SelectedItemProperty);
if (prevSelectedItem != null)
{
var prevSelectedTreeViewItem = treeView.ItemContainerGenerator.ContainerFromItem(prevSelectedItem) as TreeViewItem;
if (prevSelectedTreeViewItem != null)
{
prevSelectedTreeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, false);
}
}
}
// set new selected item
// TreeView.SelectedItemProperty is a read only property, so we must set the selection on the TreeViewItem itself
var treeViewItem = ((TreeViewItem)itemsControl).ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (treeViewItem != null)
{
treeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, true);
}
}
else if (itemsControl is TreeView)
{
// clear old selected item
var prevSelectedItem = ((TreeView)itemsControl).GetValue(TreeView.SelectedItemProperty);
if (prevSelectedItem != null)
{
var prevSelectedTreeViewItem = ((TreeView)itemsControl).ItemContainerGenerator.ContainerFromItem(prevSelectedItem) as TreeViewItem;
if (prevSelectedTreeViewItem != null)
{
prevSelectedTreeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, false);
}
}
// set new selected item
// TreeView.SelectedItemProperty is a read only property, so we must set the selection on the TreeViewItem itself
var treeViewItem = ((TreeView)itemsControl).ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (treeViewItem != null)
{
treeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, true);
}
}
else if (itemsControl is Selector)
{
((Selector)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, null);
((Selector)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, item);
}
}
/// <summary>
/// Clears the selected items.
/// </summary>
/// <param name="itemsControl">The items control.</param>
public static void ClearSelectedItems(this ItemsControl itemsControl)
{
if (itemsControl is MultiSelector)
{
if (((MultiSelector)itemsControl).CanSelectMultipleItems())
{
((MultiSelector)itemsControl).SelectedItems.Clear();
}
((MultiSelector)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, null);
}
else if (itemsControl is ListBox)
{
if (((ListBox)itemsControl).CanSelectMultipleItems())
{
((ListBox)itemsControl).SelectedItems.Clear();
((ListBox)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, null);
}
}
else if (itemsControl is TreeViewItem)
{
var treeView = ItemsControl.ItemsControlFromItemContainer((TreeViewItem)itemsControl);
treeView?.ClearSelectedItems();
}
else if (itemsControl is TreeView)
{
// clear old selected item
var prevSelectedItem = ((TreeView)itemsControl).GetValue(TreeView.SelectedItemProperty);
if (prevSelectedItem != null)
{
var prevSelectedTreeViewItem = ((TreeView)itemsControl).ItemContainerGenerator.ContainerFromItem(prevSelectedItem) as TreeViewItem;
if (prevSelectedTreeViewItem != null)
{
prevSelectedTreeViewItem.SetCurrentValue(TreeViewItem.IsSelectedProperty, false);
}
}
}
else if (itemsControl is Selector)
{
((Selector)itemsControl).SetCurrentValue(Selector.SelectedItemProperty, null);
}
}
public static object GetSelectedItem(this ItemsControl itemsControl)
{
if (itemsControl is MultiSelector)
{
return ((MultiSelector)itemsControl).SelectedItem;
}
else if (itemsControl is ListBox)
{
return ((ListBox)itemsControl).SelectedItem;
}
else if (itemsControl is TreeView)
{
return ((TreeView)itemsControl).GetValue(TreeView.SelectedItemProperty);
}
else if (itemsControl is Selector)
{
return ((Selector)itemsControl).SelectedItem;
}
return null;
}
public static IEnumerable GetSelectedItems(this ItemsControl itemsControl)
{
//if (itemsControl.GetType().IsAssignableFrom(typeof(MultiSelector)))
if (typeof(MultiSelector).IsAssignableFrom(itemsControl.GetType()))
{
return ((MultiSelector)itemsControl).SelectedItems;
}
else if (itemsControl is ListBox)
{
var listBox = (ListBox)itemsControl;
if (listBox.SelectionMode == SelectionMode.Single)
{
return Enumerable.Repeat(listBox.SelectedItem, 1);
}
else
{
return listBox.SelectedItems;
}
}
//else if (itemsControl.GetType().IsAssignableFrom(typeof(TreeView)))
else if (typeof(TreeView).IsAssignableFrom(itemsControl.GetType()))
{
return Enumerable.Repeat(((TreeView)itemsControl).SelectedItem, 1);
}
//else if (itemsControl.GetType().IsAssignableFrom(typeof(Selector)))
else if (typeof(Selector).IsAssignableFrom(itemsControl.GetType()))
{
return Enumerable.Repeat(((Selector)itemsControl).SelectedItem, 1);
}
else
{
return Enumerable.Empty<object>();
}
}
public static bool GetItemSelected(this ItemsControl itemsControl, object item)
{
if (itemsControl is MultiSelector)
{
return ((MultiSelector)itemsControl).SelectedItems.Contains(item);
}
else if (itemsControl is ListBox)
{
return ((ListBox)itemsControl).SelectedItems.Contains(item);
}
else if (itemsControl is TreeView)
{
return ((TreeView)itemsControl).SelectedItem == item;
}
else if (itemsControl is Selector)
{
return ((Selector)itemsControl).SelectedItem == item;
}
else
{
return false;
}
}
public static void SetItemSelected(this ItemsControl itemsControl, object item, bool itemSelected)
{
if (itemsControl is MultiSelector)
{
var multiSelector = (MultiSelector)itemsControl;
if (multiSelector.CanSelectMultipleItems())
{
if (itemSelected)
{
multiSelector.SelectedItems.Add(item);
}
else
{
multiSelector.SelectedItems.Remove(item);
}
}
else
{
multiSelector.SetCurrentValue(Selector.SelectedItemProperty, null);
if (itemSelected)
{
multiSelector.SetCurrentValue(Selector.SelectedItemProperty, item);
}
}
}
else if (itemsControl is ListBox)
{
var listBox = (ListBox)itemsControl;
if (listBox.SelectionMode != SelectionMode.Single)
{
if (itemSelected)
{
listBox.SelectedItems.Add(item);
}
else
{
listBox.SelectedItems.Remove(item);
}
}
else
{
listBox.SetCurrentValue(Selector.SelectedItemProperty, null);
if (itemSelected)
{
listBox.SetCurrentValue(Selector.SelectedItemProperty, item);
}
}
}
else
{
if (itemSelected)
{
itemsControl.SetSelectedItem(item);
}
else
{
itemsControl.SetSelectedItem(null);
}
}
}
private static UIElement GetClosest(ItemsControl itemsControl, IEnumerable<DependencyObject> items,
Point position, Orientation searchDirection)
{
//Console.WriteLine("GetClosest - {0}", itemsControl.ToString());
UIElement closest = null;
var closestDistance = double.MaxValue;
foreach (var i in items)
{
var uiElement = i as UIElement;
if (uiElement != null)
{
var p = uiElement.TransformToAncestor(itemsControl).Transform(new Point(0, 0));
var distance = double.MaxValue;
if (itemsControl is TreeView)
{
var xDiff = position.X - p.X;
var yDiff = position.Y - p.Y;
var hyp = Math.Sqrt(Math.Pow(xDiff, 2d) + Math.Pow(yDiff, 2d));
distance = Math.Abs(hyp);
}
else
{
var itemParent = ItemsControl.ItemsControlFromItemContainer(uiElement);
if (itemParent != null && itemParent != itemsControl)
{
searchDirection = itemParent.GetItemsPanelOrientation();
}
switch (searchDirection)
{
case Orientation.Horizontal:
distance = position.X <= p.X ? p.X - position.X : position.X - uiElement.RenderSize.Width - p.X;
break;
case Orientation.Vertical:
distance = position.Y <= p.Y ? p.Y - position.Y : position.Y - uiElement.RenderSize.Height - p.Y;
break;
}
}
if (distance < closestDistance)
{
closest = uiElement;
closestDistance = distance;
}
}
}
return closest;
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Windows;
using System.Windows.Controls;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
public static class RootElementFinder
{
public static UIElement FindRoot(DependencyObject visual)
{
var parentWindow = Window.GetWindow(visual);
var rootElement = parentWindow != null ? parentWindow.Content as UIElement : null;
if (rootElement == null)
{
if (Application.Current != null && Application.Current.MainWindow != null)
{
rootElement = Application.Current.MainWindow.Content as UIElement;
}
if (rootElement == null)
{
rootElement = visual.GetVisualAncestor<Page>() ?? visual.GetVisualAncestor<UserControl>() as UIElement;
}
}
// i don't want the fu... windows forms reference
// if (rootElement == null) {
// var elementHost = m_DragInfo.VisualSource.GetVisualAncestor<ElementHost>();
// rootElement = elementHost != null ? elementHost.Child : null;
// }
return rootElement;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Windows;
using System.Windows.Controls;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
/// <summary>
/// Extension methods for TreeViewItem
/// </summary>
public static class TreeViewItemExtensions
{
/// <summary>
/// Try get the height of the header part for the given TreeViewItem.
/// If there is no PART_Header it will return Size.Empty.
/// </summary>
/// <param name="item">The TreeViewItem.</param>
public static Size GetHeaderSize(this TreeViewItem item)
{
if (item == null)
{
return Size.Empty;
}
var header = GetHeaderControl(item);
return header != null ? new Size(header.ActualWidth, header.ActualHeight) : item.RenderSize;
}
/// <summary>
/// Try get the header part of the given TreeViewItem.
/// If there is no PART_Header it will return null.
/// </summary>
/// <param name="item">The TreeViewItem.</param>
public static FrameworkElement GetHeaderControl(this TreeViewItem item)
{
return item?.Template?.FindName("PART_Header", item) as FrameworkElement;
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Collections;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
public static class TypeUtilities
{
public static IEnumerable CreateDynamicallyTypedList(IEnumerable source)
{
var type = GetCommonBaseClass(source);
var listType = typeof(List<>).MakeGenericType(type);
var addMethod = listType.GetMethod("Add");
var list = listType.GetConstructor(Type.EmptyTypes).Invoke(null);
foreach (var o in source)
{
addMethod.Invoke(list, new[] { o });
}
return (IEnumerable)list;
}
public static Type GetCommonBaseClass(IEnumerable e)
{
var types = e.Cast<object>().Select(o => o.GetType()).ToArray<Type>();
return GetCommonBaseClass(types);
}
public static Type GetCommonBaseClass(Type[] types)
{
if (types.Length == 0)
{
return typeof(object);
}
var ret = types[0];
for (var i = 1; i < types.Length; ++i)
{
if (types[i].IsAssignableFrom(ret))
{
ret = types[i];
}
else
{
// This will always terminate when ret == typeof(object)
while (!ret.IsAssignableFrom(types[i]))
{
ret = ret.BaseType;
}
}
}
return ret;
}
/// <summary>
/// Gets the enumerable as list.
/// If enumerable is an ICollectionView then it returns the SourceCollection as list.
/// </summary>
/// <param name="enumerable">The enumerable.</param>
/// <returns>Returns a list.</returns>
public static IList TryGetList(this IEnumerable enumerable)
{
if (enumerable is ICollectionView)
{
return ((ICollectionView)enumerable).SourceCollection as IList;
}
else
{
var list = enumerable as IList;
return list ?? (enumerable != null ? enumerable.OfType<object>().ToList() : null);
}
}
}
}

View File

@@ -0,0 +1,169 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Windows.Media.Media3D;
using JetBrains.Annotations;
namespace GongSolutions.Wpf.DragDrop.Utilities
{
public static class VisualTreeExtensions
{
/// <summary>
/// Gets the next ancestor element which is a drop target.
/// </summary>
/// <param name="element">The start element.</param>
/// <returns>The first element which is a drop target.</returns>
public static UIElement TryGetNextAncestorDropTargetElement(this UIElement element)
{
if (element == null)
{
return null;
}
var ancestor = element.GetVisualAncestor<UIElement>();
while (ancestor != null)
{
if (ancestor.IsDropTarget())
{
return ancestor;
}
ancestor = ancestor.GetVisualAncestor<UIElement>();
}
return null;
}
internal static DependencyObject FindVisualTreeRoot(this DependencyObject d)
{
var current = d;
var result = d;
while (current != null)
{
result = current;
if (current is Visual || current is Visual3D)
{
break;
}
else
{
// If we're in Logical Land then we must walk
// up the logical tree until we find a
// Visual/Visual3D to get us back to Visual Land.
current = LogicalTreeHelper.GetParent(current);
}
}
return result;
}
public static T GetVisualAncestor<T>(this DependencyObject d)
where T : class
{
var item = VisualTreeHelper.GetParent(d.FindVisualTreeRoot());
while (item != null)
{
var itemAsT = item as T;
if (itemAsT != null)
{
return itemAsT;
}
item = VisualTreeHelper.GetParent(item);
}
return null;
}
/// <summary>
/// find the visual ancestor item by type
/// </summary>
public static DependencyObject GetVisualAncestor(this DependencyObject d, Type itemSearchType, [NotNull] ItemsControl itemsControl, [NotNull] Type itemContainerSearchType)
{
if (itemsControl == null) throw new ArgumentNullException(nameof(itemsControl));
if (itemContainerSearchType == null) throw new ArgumentNullException(nameof(itemContainerSearchType));
var visualTreeRoot = d.FindVisualTreeRoot();
var currentVisual = VisualTreeHelper.GetParent(visualTreeRoot);
while (currentVisual != null && itemSearchType != null)
{
var currentVisualType = currentVisual.GetType();
if (currentVisualType == itemSearchType || currentVisualType.IsSubclassOf(itemSearchType))
{
if (currentVisual is TreeViewItem || itemsControl.ItemContainerGenerator.IndexFromContainer(currentVisual) != -1)
{
return currentVisual;
}
}
if (itemContainerSearchType.IsAssignableFrom(currentVisualType))
{
// ok, we found an ItemsControl (maybe an empty)
return null;
}
currentVisual = VisualTreeHelper.GetParent(currentVisual);
}
return null;
}
/// <summary>
/// find the visual ancestor by type and go through the visual tree until the given itemsControl will be found
/// </summary>
public static DependencyObject GetVisualAncestor(this DependencyObject d, Type itemSearchType, [NotNull] ItemsControl itemsControl)
{
if (itemsControl == null) throw new ArgumentNullException(nameof(itemsControl));
var visualTreeRoot = d.FindVisualTreeRoot();
var currentVisual = VisualTreeHelper.GetParent(visualTreeRoot);
DependencyObject lastFoundItemByType = null;
while (currentVisual != null && itemSearchType != null)
{
if (currentVisual == itemsControl)
{
return lastFoundItemByType;
}
var currentVisualType = currentVisual.GetType();
if ((currentVisualType == itemSearchType || currentVisualType.IsSubclassOf(itemSearchType))
&& (itemsControl.ItemContainerGenerator.IndexFromContainer(currentVisual) != -1))
{
lastFoundItemByType = currentVisual;
}
currentVisual = VisualTreeHelper.GetParent(currentVisual);
}
return lastFoundItemByType;
}
public static T GetVisualDescendent<T>(this DependencyObject d)
where T : DependencyObject
{
return d.GetVisualDescendents<T>().FirstOrDefault();
}
public static IEnumerable<T> GetVisualDescendents<T>(this DependencyObject d)
where T : DependencyObject
{
var childCount = VisualTreeHelper.GetChildrenCount(d);
for (var n = 0; n < childCount; n++)
{
var child = VisualTreeHelper.GetChild(d, n);
if (child is T)
{
yield return (T)child;
}
foreach (var match in GetVisualDescendents<T>(child))
{
yield return match;
}
}
yield break;
}
}
}