123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- using System.Collections;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.Windows.Media;
- namespace Waaagh.Behaviors {
- sealed public class ItemsDraggable {
- #region Drag Drop Data Format String
- static readonly string DraggableDataFormat = "DraggableData";
- static readonly string DraggableCollectionFormat = "DraggableCollection";
- #endregion
- #region Enabled
- static public bool GetEnabled(DependencyObject obj) {
- return (bool)obj.GetValue(EnabledProperty);
- }
- static public void SetEnabled(DependencyObject obj, bool value) {
- obj.SetValue(EnabledProperty, value);
- }
- static public readonly DependencyProperty EnabledProperty =
- DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(ItemsDraggable),
- new PropertyMetadata(false, OnEnabledChanged));
- static private void OnEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) {
- if (sender is ItemsControl itemsControl == false) {
- throw new InvalidOperationException("The attached control is not an 'ItemsControl'.");
- }
- itemsControl.AllowDrop = false;
- itemsControl.MouseMove -= ItemsDraggable_MouseMove;
- itemsControl.DragEnter -= ItemsDraggable_DragEnter;
- itemsControl.DragOver -= ItemsDraggable_DragOver;
- itemsControl.DragLeave -= ItemsDraggable_DragLeave;
- itemsControl.Drop -= ItemsDraggable_Drop;
- if (GetEnabled(itemsControl) == true) {
- itemsControl.AllowDrop = true;
- itemsControl.MouseMove += ItemsDraggable_MouseMove;
- itemsControl.DragEnter += ItemsDraggable_DragEnter;
- itemsControl.DragOver += ItemsDraggable_DragOver;
- itemsControl.DragLeave += ItemsDraggable_DragLeave;
- itemsControl.Drop += ItemsDraggable_Drop;
- }
- }
- public static Func<object, Type, IList?> GetQueryTargetCollection(DependencyObject obj) {
- return (Func<object, Type, IList?>)obj.GetValue(QueryTargetCollectionProperty);
- }
- public static void SetQueryTargetCollection(DependencyObject obj, Func<object, Type, IList?> value) {
- obj.SetValue(QueryTargetCollectionProperty, value);
- }
- public static readonly DependencyProperty QueryTargetCollectionProperty =
- DependencyProperty.RegisterAttached("QueryTargetCollection", typeof(Func<object, Type, IList?>), typeof(ItemsDraggable), new PropertyMetadata(null));
- #endregion
- #region Drag Drop Event
- static private void ItemsDraggable_MouseMove(object sender, MouseEventArgs args) {
- if (args.LeftButton != MouseButtonState.Pressed) {
- return;
- }
- if (sender is ItemsControl source == false) {
- return;
- }
- if (source.ItemsSource is IList == false) {
- return;
- }
- if (GetElement(source, args.GetPosition(source)) is Control sourceControl == false) {
- return;
- }
- if (GetParent(sourceControl) is ItemsControl sourceItemsControl == false) {
- return;
- }
- DataObject data = new DataObject();
- data.SetData(DraggableDataFormat, sourceControl.DataContext);
- data.SetData(DraggableCollectionFormat, sourceItemsControl.ItemsSource);
- DragDrop.DoDragDrop(sourceItemsControl, data, DragDropEffects.Move);
- }
- static private void ItemsDraggable_DragEnter(object sender, DragEventArgs args) {
- }
- static private void ItemsDraggable_DragOver(object sender, DragEventArgs args) {
- }
- static private void ItemsDraggable_DragLeave(object sender, DragEventArgs args) {
- }
- static private void ItemsDraggable_Drop(object sender, DragEventArgs args) {
- if (args.Effects == DragDropEffects.None) {
- return;
- }
- if (sender is ItemsControl target == false) {
- return;
- }
- // 获取 放置目标
- if (GetElement(target, args.GetPosition(target)) is Control targetControl == false) {
- return;
- }
- if (GetParent(targetControl) is ItemsControl targetItemsControl == false) {
- return;
- }
- if (targetItemsControl.ItemsSource is IList targetCollection == false) {
- return;
- }
- // 获取 拖拽源
- object? sourceData = args.Data.GetData(DraggableDataFormat) as object;
- IList? sourceCollection = args.Data.GetData(DraggableCollectionFormat) as IList;
- if (sourceData == null || sourceCollection == null) {
- return;
- }
- // 判断 集合元素类型
- object? targetData = targetControl.DataContext;
- if (CheckCollectionElementType(sourceCollection, targetCollection) == false) {
- IList? collection = GetQueryTargetCollection(targetItemsControl)?.Invoke(targetControl.DataContext, sourceData.GetType());
- if (collection == null || CheckCollectionElementType(sourceCollection, collection) == false) {
- return;
- }
- targetCollection = collection;
- targetData = null; // 置 targetData 为 null, 尝试将 sourceData 添加到 targetCollection 末尾
- }
- // 执行 拖拽影响
- DoDragDropEffects(args.Effects, sourceCollection, sourceData, targetCollection, targetData);
- }
- #endregion
- #region Drag Drop Effects
- static private void DoDragDropEffects(DragDropEffects effects, IList sourceCollection, object sourceData, IList targetCollection, object? targetData) {
- if (sourceCollection == null || sourceData == null || targetCollection == null) {
- return;
- }
- if (object.ReferenceEquals(sourceData, targetData)) {
- return;
- }
- switch (effects) {
- case DragDropEffects.Scroll: {
- break;
- }
- case DragDropEffects.All: {
- break;
- }
- case DragDropEffects.Copy: {
- break;
- }
- case DragDropEffects.Move: {
- DoMoveEffect(sourceCollection, sourceData, targetCollection, targetData);
- break;
- }
- case DragDropEffects.Link: {
- break;
- }
- default: {
- break;
- }
- }
- }
- static private void DoMoveEffect(IList sourceCollection, object sourceData, IList targetCollection, object? targetData) {
- int oldIndex = sourceCollection.IndexOf(sourceData);
- int newIndex = targetCollection.IndexOf(targetData);
- if (newIndex == -1) {
- newIndex = targetCollection.Count - 1;
- }
- if (object.ReferenceEquals(sourceCollection, targetCollection)) {
- if (oldIndex == newIndex) {
- return;
- }
- // 同个集合, 移除元素后下标可能变化
- if (oldIndex < newIndex) {
- newIndex -= 1;
- }
- }
- sourceCollection.RemoveAt(oldIndex);
- targetCollection.Insert(newIndex + 1, sourceData);
- }
- #endregion
- #region Helper
- static private bool GetDragDropEventSource(ref ItemsControl parent, out Control child, Func<IInputElement, Point> getPosition) {
- if (parent != null) {
- ItemContainerGenerator generator = parent.ItemContainerGenerator;
- for (int i = generator.Items.Count - 1; i >= 0; --i) {
- if (generator.ContainerFromIndex(i) is Control control == false) {
- continue;
- }
- Point position = getPosition(control);
- if (position.X < 0 || position.X > control.ActualWidth ||
- position.Y < 0 || position.Y > control.ActualHeight) {
- continue;
- }
- if (control is ContentControl) {
- child = control;
- return true;
- }
- if (control is ItemsControl itemsControl) {
- ItemsControl prevParent = parent;
- parent = itemsControl;
- if (GetDragDropEventSource(ref parent, out child, getPosition) == false) {
- child = parent;
- parent = prevParent;
- }
- return true;
- }
- }
- }
- child = default!;
- return false;
- }
- static private Control? GetElement(ItemsControl source, Point point) {
- if (GetItemContainerType(source) is Type type == false) {
- return null;
- }
- DependencyObject? dp = source.InputHitTest(point) as DependencyObject;
- while (dp != null) {
- if (dp.GetType().Equals(type)) {
- break;
- }
- dp = VisualTreeHelper.GetParent(dp);
- }
- return dp as Control;
- }
- static private ItemsControl? GetParent(Control control) {
- for (DependencyObject dp = VisualTreeHelper.GetParent(control); dp != null; dp = VisualTreeHelper.GetParent(dp)) {
- if (dp is ItemsControl parent && parent.ItemContainerGenerator.ContainerFromItem(control.DataContext) != null) {
- return parent;
- }
- }
- return null;
- }
- static private Type? GetItemContainerType(ItemsControl source) {
- if (source == null) {
- return null;
- }
- if (source is ListView) {
- return typeof(ListViewItem);
- }
- else if (source is ListBox) {
- return typeof(ListBoxItem);
- }
- else if (source is TreeView || source is TreeViewItem) {
- return typeof(TreeViewItem);
- }
- // else if (source is GridView) {
- // return typeof(GridViewColumn);
- // }
- if (source.Items.Count > 0) {
- return source.ItemContainerGenerator.ContainerFromIndex(0)?.GetType();
- }
- return null;
- }
- static private bool CheckCollectionElementType(IList collection1, IList collection2) {
- return collection1.GetType().GetGenericArguments()[0] == collection2.GetType().GetGenericArguments()[0];
- }
- #endregion
- }
- }
|