123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- using System.Collections;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- 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 sourceItemsControl == false) {
- return;
- }
- if (sourceItemsControl.ItemsSource is IList == false) {
- return;
- }
- if (GetDragDropEventSource(ref sourceItemsControl, out Control sourceControl, args.GetPosition) == 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 targetItemsControl == false) {
- return;
- }
- // 获取 拖拽源
- object? sourceData = args.Data.GetData(DraggableDataFormat) as object;
- IList? sourceCollection = args.Data.GetData(DraggableCollectionFormat) as IList;
- if (sourceData == null || sourceCollection == null) {
- return;
- }
- // 获取 放置目标
- if (GetDragDropEventSource(ref targetItemsControl, out Control targetControl, args.GetPosition) == false) {
- return;
- }
- if (targetItemsControl.ItemsSource is IList targetCollection == false) {
- 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 bool CheckCollectionElementType(IList collection1, IList collection2) {
- return collection1.GetType().GetGenericArguments()[0] == collection2.GetType().GetGenericArguments()[0];
- }
- #endregion
- }
- }
|