123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- 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 Dragging Data Object
- private static DataObject? GetDraggingData(DependencyObject obj) {
- return (DataObject?)obj.GetValue(DraggingDataProperty);
- }
- private static void SetDraggingData(DependencyObject obj, DataObject? value) {
- obj.SetValue(DraggingDataProperty, value);
- }
- private static readonly DependencyProperty DraggingDataProperty = DependencyProperty.RegisterAttached(
- "DraggingData", typeof(DataObject), typeof(ItemsDraggable), new PropertyMetadata(null));
- #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'.");
- }
- // if (itemsControl.ItemsSource is IList == false) {
- // throw new InvalidOperationException("The attached control must have an 'ItemsSource' implements 'IList'.");
- // }
- itemsControl.AllowDrop = false;
- itemsControl.PreviewMouseLeftButtonDown -= ItemsDraggable_PreviewMouseLeftButtonDown;
- 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.PreviewMouseLeftButtonDown += ItemsDraggable_PreviewMouseLeftButtonDown;
- itemsControl.MouseMove += ItemsDraggable_MouseMove;
- itemsControl.DragEnter += ItemsDraggable_DragEnter;
- itemsControl.DragOver += ItemsDraggable_DragOver;
- itemsControl.DragLeave += ItemsDraggable_DragLeave;
- itemsControl.Drop += ItemsDraggable_Drop;
- }
- }
- #endregion
- #region Drag Drop Event
- private static void ItemsDraggable_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs args) {
- if (sender is ItemsControl control == false) {
- return;
- }
- if (control.ItemsSource is IList == false) {
- return;
- }
- if (GetElement(control, args.GetPosition(control)) 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);
- SetDraggingData(control, data);
- }
- static private void ItemsDraggable_MouseMove(object sender, MouseEventArgs args) {
- if (args.LeftButton != MouseButtonState.Pressed) {
- return;
- }
- if (sender is ItemsControl source == false) {
- return;
- }
- if (GetDraggingData(source) is DataObject data == false) {
- return;
- }
- SetDraggingData(source, null);
- DragDrop.DoDragDrop(source, 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 control == false) {
- return;
- }
- // 获取 放置目标
- if (GetElement(control, args.GetPosition(control)) is Control targetControl == false) {
- return;
- }
- if (GetParent(targetControl) is ItemsControl targetItemsControl == false) {
- return;
- }
- object? targetData = targetControl.DataContext;
- IList? targetCollection = targetItemsControl.ItemsSource as IList;
- if (targetCollection == null) {
- return;
- }
- // 获取 拖拽源
- object? sourceData = args.Data.GetData(DraggableDataFormat) as object;
- IList? sourceCollection = args.Data.GetData(DraggableCollectionFormat) as IList;
- if (sourceData == null || sourceCollection == null) {
- return;
- }
- // 执行 拖拽影响
- DoDragDropEffects(control, args.Effects, sourceCollection, sourceData, targetCollection, targetData);
- }
- #endregion
- #region Drag Drop Effects
- public delegate void DoEffectsCallbackHandler(object sender, DoEffectsCallbackArgs args);
- public class DoEffectsCallbackArgs {
- public IList SourceCollection { get; }
- public object SourceData { get; }
- public IList TargetCollection { get; }
- public object? TargetData { get; }
- public DoEffectsCallbackArgs(IList sourceCollection, object sourceData, IList targetCollection, object? targetData) {
- SourceCollection = sourceCollection;
- SourceData = sourceData;
- TargetCollection = targetCollection;
- TargetData = targetData;
- }
- }
- static private void DoDragDropEffects(ItemsControl control, 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: {
- GetDoMoveEffect(control)?.Invoke(control, new DoEffectsCallbackArgs(sourceCollection, sourceData, targetCollection, targetData));
- break;
- }
- case DragDropEffects.Link: {
- break;
- }
- default: {
- break;
- }
- }
- }
- #region Do Move Effect Callback
- public static DoEffectsCallbackHandler GetDoMoveEffect(DependencyObject obj) {
- return (DoEffectsCallbackHandler)obj.GetValue(DoMoveEffectProperty);
- }
- public static void SetDoMoveEffect(DependencyObject obj, DoEffectsCallbackHandler value) {
- obj.SetValue(DoMoveEffectProperty, value);
- }
- public static readonly DependencyProperty DoMoveEffectProperty = DependencyProperty.RegisterAttached(
- "DoMoveEffect", typeof(DoEffectsCallbackHandler), typeof(ItemsDraggable), new PropertyMetadata(null));
- #endregion
- #endregion
- #region Helper
- 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;
- }
- #endregion
- }
|