mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-05-01 13:39:28 +08:00
添加项目文件。
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user