Advertisement
RichardD

WPF Drag+Drop

Feb 11th, 2013
2,051
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 31.00 KB | None | 0 0
  1. /*
  2. Based on code originally published by Jaime Rodriguez:
  3. http://blogs.msdn.com/b/jaimer/archive/2007/07/12/drag-drop-in-wpf-explained-end-to-end.aspx
  4. */
  5.  
  6.  
  7. internal static class Extensions
  8. {
  9.    private const int GWL_EXSTYLE = -20;
  10.  
  11.    [StructLayout(LayoutKind.Sequential)]
  12.    public struct POINT
  13.    {
  14.       public int X;
  15.       public int Y;
  16.    }
  17.  
  18.    [DllImport("user32.dll", SetLastError = true)]
  19.    [return: MarshalAs(UnmanagedType.Bool)]
  20.    private static extern bool GetCursorPos(out POINT pt);
  21.  
  22.    public static POINT? GetMouseCursorPosition()
  23.    {
  24.       POINT result;
  25.       if (!GetCursorPos(out result)) return null;
  26.       return result;
  27.    }
  28.  
  29.  
  30.    [DllImport("user32.dll", SetLastError = true)]
  31.    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
  32.  
  33.    [DllImport("user32.dll", SetLastError = true)]
  34.    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int nValue);
  35.  
  36.    public static void SetNativeExtendedWindowStyle(this Window window, int windowStyle, bool enable)
  37.    {
  38.       if (window == null) throw new ArgumentNullException("window");
  39.  
  40.       IntPtr hWnd = new WindowInteropHelper(window).Handle;
  41.       if (hWnd == IntPtr.Zero) return;
  42.  
  43.       int style = GetWindowLong(hWnd, GWL_EXSTYLE);
  44.       if (enable)
  45.       {
  46.          style |= windowStyle;
  47.       }
  48.       else
  49.       {
  50.          style &= ~windowStyle;
  51.       }
  52.  
  53.       SetWindowLong(hWnd, GWL_EXSTYLE, style);
  54.    }
  55.  
  56.  
  57.    public static T FindVisualParent<T>(this DependencyObject element, DependencyObject stopAt = null) where T : DependencyObject
  58.    {
  59.       if (element == null) throw new ArgumentNullException("element");
  60.  
  61.       DependencyObject parent = element;
  62.       var result = parent as T;
  63.  
  64.       while (result == null && parent != null && parent != stopAt)
  65.       {
  66.          parent = VisualTreeHelper.GetParent(parent);
  67.          result = parent as T;
  68.       }
  69.  
  70.       return result;
  71.    }
  72. }
  73.  
  74. [Flags]
  75. public enum DragDropProviderActions
  76. {
  77.    None = 0,
  78.    Data = 0x01,
  79.    Visual = 0x02,
  80.    Feedback = 0x04,
  81.    ContinueDrag = 0x08,
  82.    Clone = 0x10,
  83.    MultiFormatData = 0x20,
  84.    Unparent = 0x8000,
  85. }
  86.  
  87. public interface IDataDropObjectProvider
  88. {
  89.    DragDropProviderActions SupportedActions { get; }
  90.    object GetData();
  91.    void AppendData(ref IDataObject data, MouseEventArgs e);
  92.    UIElement GetVisual(MouseEventArgs e);
  93.    void GiveFeedback(GiveFeedbackEventArgs args);
  94.    void ContinueDrag(QueryContinueDragEventArgs args);
  95.    bool UnParent();
  96. }
  97.  
  98. internal sealed class DragDataWrapper
  99. {
  100.    public object Data;
  101.    public bool AllowChildrenRemove;
  102.    public IDataDropObjectProvider Shim;
  103. }
  104.  
  105. public interface IDataDropTarget
  106. {
  107.    bool CanDrop(DragEventArgs args, object rawData);
  108.    void DataDropped(DragEventArgs args, object rawData);
  109. }
  110.  
  111. public interface IDropTargetHilighter : IHideObjectMembers
  112. {
  113.    object AddHilight(UIElement target);
  114.    void RemoveHilight(UIElement target, object previousState);
  115. }
  116.  
  117. internal sealed class DragAdorner : Adorner
  118. {
  119.    private readonly UIElement _child;
  120.    private readonly double _xCenter;
  121.    private readonly double _yCenter;
  122.    private double _leftOffset;
  123.    private double _topOffset;
  124.  
  125.    public DragAdorner(UIElement owner, UIElement child, bool useVisualBrush, double opacity) : base(owner)
  126.    {
  127.       if (!useVisualBrush)
  128.       {
  129.          _child = child;
  130.       }
  131.       else
  132.       {
  133.          var size = GetRealSize(child);
  134.          _xCenter = size.Width / 2;
  135.          _yCenter = size.Height / 2;
  136.  
  137.          _child = new Rectangle
  138.          {
  139.             RadiusX = 3,
  140.             RadiusY = 3,
  141.             Width = size.Width,
  142.             Height = size.Height,
  143.             Fill = new VisualBrush(child)
  144.             {
  145.                Opacity = opacity,
  146.                AlignmentX = AlignmentX.Left,
  147.                AlignmentY = AlignmentY.Top,
  148.                Stretch = Stretch.None,
  149.             },
  150.          };
  151.       }
  152.    }
  153.  
  154.    protected override int VisualChildrenCount
  155.    {
  156.       get { return 1; }
  157.    }
  158.  
  159.    public double LeftOffset
  160.    {
  161.       get
  162.       {
  163.          return _leftOffset + _xCenter;
  164.       }
  165.       set
  166.       {
  167.          _leftOffset = value - _xCenter;
  168.          UpdatePosition();
  169.       }
  170.    }
  171.  
  172.    public double TopOffset
  173.    {
  174.       get
  175.       {
  176.          return _topOffset + _yCenter;
  177.       }
  178.       set
  179.       {
  180.          _topOffset = value - _yCenter;
  181.          UpdatePosition();
  182.       }
  183.    }
  184.  
  185.    private static Size GetRealSize(UIElement child)
  186.    {
  187.       return child == null ? Size.Empty : child.RenderSize;
  188.    }
  189.  
  190.    public void UpdatePosition(Point point)
  191.    {
  192.       _leftOffset = point.X;
  193.       _topOffset = point.Y;
  194.       UpdatePosition();
  195.    }
  196.  
  197.    public void UpdatePosition()
  198.    {
  199.       var adorner = Parent as AdornerLayer;
  200.       if (adorner != null) adorner.Update(AdornedElement);
  201.    }
  202.  
  203.    protected override Visual GetVisualChild(int index)
  204.    {
  205.       if (0 != index) throw new ArgumentOutOfRangeException("index");
  206.       return _child;
  207.    }
  208.  
  209.    protected override Size MeasureOverride(Size availableSize)
  210.    {
  211.       _child.Measure(availableSize);
  212.       return _child.DesiredSize;
  213.    }
  214.  
  215.    protected override Size ArrangeOverride(Size finalSize)
  216.    {
  217.       _child.Arrange(new Rect(_child.DesiredSize));
  218.       return finalSize;
  219.    }
  220.  
  221.    public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
  222.    {
  223.       var result = new GeneralTransformGroup();
  224.       result.Children.Add(new TranslateTransform(_leftOffset, _topOffset));
  225.  
  226.       var baseTransform = base.GetDesiredTransform(transform);
  227.       if (baseTransform != null) result.Children.Add(baseTransform);
  228.  
  229.       return result;
  230.    }
  231. }
  232.  
  233. internal sealed class DragDropWindow : Window
  234. {
  235.    private const int WS_EX_LAYERED = 0x00080000;
  236.    private const int WS_EX_TRANSPARENT = 0x00000020;
  237.  
  238.    private DragDropWindow()
  239.    {
  240.       InitializeComponent();
  241.    }
  242.  
  243.    public static DragDropWindow Create(UIElement dragElement)
  244.    {
  245.       var result = new DragDropWindow();
  246.       result.SetContent(dragElement);
  247.       result.Show();
  248.       return result;
  249.    }
  250.  
  251.    private void InitializeComponent()
  252.    {
  253.       WindowStyle = WindowStyle.None;
  254.       AllowsTransparency = true;
  255.       AllowDrop = false;
  256.       Background = null;
  257.       IsHitTestVisible = false;
  258.       SizeToContent = SizeToContent.WidthAndHeight;
  259.       Topmost = true;
  260.       ShowInTaskbar = false;
  261.    }
  262.  
  263.    private void InitializeWindow()
  264.    {
  265.       this.SetNativeExtendedWindowStyle(WS_EX_LAYERED | WS_EX_TRANSPARENT, true);
  266.    }
  267.  
  268.    protected override void OnSourceInitialized(EventArgs e)
  269.    {
  270.       base.OnSourceInitialized(e);
  271.       InitializeWindow();
  272.    }
  273.  
  274.    public void SetContent(UIElement dragElement)
  275.    {
  276.       var element = dragElement as FrameworkElement;
  277.       if (element != null)
  278.       {
  279.          Content = new Rectangle
  280.          {
  281.             Width = element.ActualWidth,
  282.             Height = element.ActualHeight,
  283.             Fill = new VisualBrush(dragElement)
  284.          };
  285.       }
  286.    }
  287.  
  288.    public void UpdatePosition()
  289.    {
  290.       var position = SafeNativeMethods.GetMouseCursorPosition();
  291.       if (position != null)
  292.       {
  293.          var value = position.GetValueOrDefault();
  294.          Left = value.X;
  295.          Top = value.Y;
  296.       }
  297.    }
  298. }
  299.  
  300. public sealed class DropTargetVisualStateHilighter : IDropTargetHilighter
  301. {
  302.    public const string HighlightVisualState = "DragOver";
  303.    public const string NoHighlightVisualState = "NoDrag";
  304.  
  305.    public object AddHilight(UIElement target)
  306.    {
  307.       var el = target as FrameworkElement;
  308.       if (el != null) VisualStateManager.GoToState(el, HighlightVisualState, true);
  309.       return null;
  310.    }
  311.  
  312.    public void RemoveHilight(UIElement target, object previousState)
  313.    {
  314.       var el = target as FrameworkElement;
  315.       if (el != null) VisualStateManager.GoToState(el, NoHighlightVisualState, true);
  316.    }
  317. }
  318.  
  319. public class DragHelper : DependencyObject
  320. {
  321.    private static readonly string DragDataWrapperKey = typeof(DragDataWrapper).ToString();
  322.    private static readonly Point EmptyStartPoint = new Point(double.NaN, double.NaN);
  323.  
  324.    private readonly IDataDropObjectProvider _callback;
  325.    private readonly UIElement _dragSource;
  326.    private readonly UIElement _dragScope;
  327.    private DragDropEffects _allowedEffects = DragDropEffects.Copy | DragDropEffects.Move;
  328.    private double _opacity = 0.7;
  329.    private bool _isDragging;
  330.    private Point _startPoint = EmptyStartPoint;
  331.    private AdornerLayer _layer;
  332.    private DragAdorner _adorner;
  333.    private DragDropWindow _dragdropWindow;
  334.    private bool _mouseLeftScope;
  335.  
  336.    public DragHelper(UIElement source, IDataDropObjectProvider callback = null, UIElement dragScope = null)
  337.    {
  338.       if (source == null) throw new ArgumentNullException("source");
  339.       if (callback == null) callback = BuildDefaultProvider(source);
  340.  
  341.       _dragSource = source;
  342.       _callback = callback;
  343.       _dragScope = dragScope;
  344.  
  345.       source.PreviewMouseLeftButtonDown += DragSource_PreviewMouseLeftButtonDown;
  346.       source.PreviewMouseMove += DragSource_PreviewMouseMove;
  347.    }
  348.  
  349.    public UIElement DragSource
  350.    {
  351.       get { return _dragSource; }
  352.    }
  353.  
  354.    public UIElement DragScope
  355.    {
  356.       get { return _dragScope; }
  357.    }
  358.  
  359.    public double Opacity
  360.    {
  361.       get { return _opacity; }
  362.       set { _opacity = value; }
  363.    }
  364.  
  365.    public bool IsDragging
  366.    {
  367.       get { return _isDragging; }
  368.       protected set { _isDragging = value; }
  369.    }
  370.  
  371.    public DragDropEffects AllowedEffects
  372.    {
  373.       get { return _allowedEffects; }
  374.       set { _allowedEffects = value; }
  375.    }
  376.  
  377.    protected bool AllowsLink
  378.    {
  379.       get { return (DragDropEffects.Link & _allowedEffects) == DragDropEffects.Link; }
  380.    }
  381.  
  382.    protected bool AllowsMove
  383.    {
  384.       get { return (DragDropEffects.Move & _allowedEffects) == DragDropEffects.Move; }
  385.    }
  386.  
  387.    protected bool AllowsCopy
  388.    {
  389.       get { return (DragDropEffects.Copy & _allowedEffects) == DragDropEffects.Copy; }
  390.    }
  391.  
  392.    private static IDataDropObjectProvider BuildDefaultProvider(UIElement source)
  393.    {
  394.       var callback = source as IDataDropObjectProvider;
  395.       if (callback != null) return callback;
  396.  
  397.       var list = source as Selector;
  398.       if (list != null) return new ListBoxDragDropDataProvider(list);
  399.  
  400.       return null;
  401.    }
  402.  
  403.    private void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  404.    {
  405.       _startPoint = e.GetPosition(DragScope);
  406.    }
  407.  
  408.    private void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
  409.    {
  410.       if (!_isDragging && _startPoint != EmptyStartPoint && e.LeftButton == MouseButtonState.Pressed && !IsWithinScrollBar(e.OriginalSource, e.Source))
  411.       {
  412.          Point position = e.GetPosition(DragScope);
  413.          if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
  414.             Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
  415.          {
  416.             StartDrag(e);
  417.          }
  418.       }
  419.    }
  420.  
  421.    private void DragScope_DragLeave(object sender, DragEventArgs args)
  422.    {
  423.       if (ReferenceEquals(_dragSource, args.OriginalSource))
  424.       {
  425.          _mouseLeftScope = true;
  426.       }
  427.    }
  428.  
  429.    private void DragSource_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
  430.    {
  431.       if (!_isDragging)
  432.       {
  433.          e.Action = DragAction.Cancel;
  434.          e.Handled = true;
  435.       }
  436.       else if (_dragScope == null)
  437.       {
  438.          if (_dragdropWindow != null)
  439.          {
  440.             _dragdropWindow.UpdatePosition();
  441.          }
  442.       }
  443.       else
  444.       {
  445.          if (_adorner != null)
  446.          {
  447.             Point p = Mouse.GetPosition(_dragScope);
  448.             _adorner.UpdatePosition(p);
  449.          }
  450.          if (_mouseLeftScope)
  451.          {
  452.             e.Action = DragAction.Cancel;
  453.             e.Handled = true;
  454.          }
  455.       }
  456.    }
  457.  
  458.    private void DragScope_DragOver(object sender, DragEventArgs e)
  459.    {
  460.       if (_adorner != null)
  461.       {
  462.          Point p = e.GetPosition(_dragScope);
  463.          _adorner.UpdatePosition(p);
  464.       }
  465.    }
  466.  
  467.    protected virtual bool IsWithinScrollBar(object originalSource, object source)
  468.    {
  469.       var control = originalSource as DependencyObject;
  470.       return control != null && control.FindVisualParent<ScrollBar>(source as DependencyObject) != null;
  471.    }
  472.  
  473.    protected virtual DragDropEffects GetDragDropEffects()
  474.    {
  475.       var effects = DragDropEffects.None;
  476.       bool ctrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
  477.       bool shift = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
  478.  
  479.       if (ctrl && shift && AllowsLink)
  480.       {
  481.          effects |= DragDropEffects.Link;
  482.       }
  483.       else if (ctrl && AllowsCopy)
  484.       {
  485.          effects |= DragDropEffects.Copy;
  486.       }
  487.       else
  488.       {
  489.          if (AllowsMove) effects |= DragDropEffects.Move;
  490.          if (AllowsCopy) effects |= DragDropEffects.Copy;
  491.       }
  492.  
  493.       return effects;
  494.    }
  495.  
  496.    protected virtual void StartDrag(MouseEventArgs args)
  497.    {
  498.       if (args == null) throw new ArgumentNullException("args");
  499.  
  500.       IDataObject data;
  501.       UIElement dragElement;
  502.  
  503.       if (_callback == null)
  504.       {
  505.          dragElement = args.OriginalSource as UIElement;
  506.          data = (dragElement == null) ? null : new DataObject(typeof(UIElement).ToString(), dragElement);
  507.       }
  508.       else
  509.       {
  510.          var wrapper = new DragDataWrapper
  511.          {
  512.             Shim = _callback,
  513.             AllowChildrenRemove = (DragDropProviderActions.Unparent & _callback.SupportedActions) == DragDropProviderActions.Unparent,
  514.          };
  515.  
  516.          data = new DataObject(DragDataWrapperKey, wrapper);
  517.  
  518.          if ((DragDropProviderActions.MultiFormatData & _callback.SupportedActions) == DragDropProviderActions.MultiFormatData)
  519.          {
  520.             _callback.AppendData(ref data, args);
  521.          }
  522.          if ((DragDropProviderActions.Data & _callback.SupportedActions) == DragDropProviderActions.Data)
  523.          {
  524.             wrapper.Data = _callback.GetData();
  525.          }
  526.          if ((DragDropProviderActions.Visual & _callback.SupportedActions) == DragDropProviderActions.Visual)
  527.          {
  528.             dragElement = _callback.GetVisual(args);
  529.          }
  530.          else
  531.          {
  532.             dragElement = args.OriginalSource as UIElement;
  533.          }
  534.       }
  535.  
  536.       if (data != null && dragElement != null && _dragSource != null && !ReferenceEquals(dragElement, _dragSource))
  537.       {
  538.          DragDropEffects effects = GetDragDropEffects();
  539.          if (_dragScope != null)
  540.          {
  541.             // In-window drag:
  542.             _layer = AdornerLayer.GetAdornerLayer(_dragScope);
  543.             _adorner = new DragAdorner(_dragScope, dragElement, true, _opacity);
  544.             _layer.Add(_adorner);
  545.  
  546.             bool previousAllowDrop = _dragScope.AllowDrop;
  547.             _dragScope.AllowDrop = true;
  548.  
  549.             _isDragging = true;
  550.             _mouseLeftScope = false;
  551.  
  552.             DragDrop.AddPreviewDragOverHandler(_dragScope, DragScope_DragOver);
  553.             DragDrop.AddPreviewDragLeaveHandler(_dragScope, DragScope_DragLeave);
  554.             DragDrop.AddPreviewQueryContinueDragHandler(_dragSource, DragSource_QueryContinueDrag);
  555.  
  556.             try
  557.             {
  558.                DragDropEffects resultEffects = DragDrop.DoDragDrop(_dragSource, data, effects);
  559.                DragFinished(resultEffects);
  560.             }
  561.             finally
  562.             {
  563.                DragDrop.RemovePreviewDragOverHandler(_dragScope, DragScope_DragOver);
  564.                DragDrop.RemovePreviewDragLeaveHandler(_dragScope, DragScope_DragLeave);
  565.                DragDrop.RemovePreviewQueryContinueDragHandler(_dragSource, DragSource_QueryContinueDrag);
  566.  
  567.                _dragScope.AllowDrop = previousAllowDrop;
  568.                _startPoint = EmptyStartPoint;
  569.                _isDragging = false;
  570.  
  571.                if (_layer != null) _layer.Remove(_adorner);
  572.                _adorner = null;
  573.                _layer = null;
  574.             }
  575.          }
  576.          else
  577.          {
  578.             // Cross-window / process drag:
  579.  
  580.             _isDragging = true;
  581.             _dragdropWindow = DragDropWindow.Create(dragElement);
  582.  
  583.             DragDrop.AddPreviewQueryContinueDragHandler(_dragSource, DragSource_QueryContinueDrag);
  584.  
  585.             try
  586.             {
  587.                DragDropEffects resultEffects = DragDrop.DoDragDrop(_dragSource, data, effects);
  588.                DragFinished(resultEffects);
  589.             }
  590.             finally
  591.             {
  592.                DragDrop.RemovePreviewQueryContinueDragHandler(_dragSource, DragSource_QueryContinueDrag);
  593.  
  594.                _dragdropWindow.Close();
  595.                _dragdropWindow = null;
  596.  
  597.                _startPoint = EmptyStartPoint;
  598.                _isDragging = false;
  599.             }
  600.          }
  601.       }
  602.    }
  603.  
  604.    protected virtual void DragFinished(DragDropEffects resultEffects)
  605.    {
  606.       Mouse.Capture(null);
  607.    }
  608. }
  609.  
  610. public class DropHelper
  611. {
  612.    private static readonly string UIElementKey = typeof(UIElement).ToString();
  613.    private static readonly string DragDataWrapperKey = typeof(DragDataWrapper).ToString();
  614.    private static readonly string[] DefaultDataTypes = new[] { DragDataWrapperKey, UIElementKey, DataFormats.Text };
  615.  
  616.    private readonly UIElement _dropTarget;
  617.    private readonly IDataDropTarget _dataDropTarget;
  618.    private DragDropEffects _allowedEffects = DragDropEffects.Copy | DragDropEffects.Move;
  619.    private string[] _allowedDataTypes;
  620.  
  621.    private readonly IDropTargetHilighter _defaultHilighter = new DropTargetVisualStateHilighter();
  622.    private readonly IDropTargetHilighter _hilighter;
  623.    private object _hilighterState;
  624.  
  625.    public DropHelper(UIElement dropTarget, IDataDropTarget dataDropTarget = null, IDropTargetHilighter targetHilighter = null)
  626.    {
  627.       if (dropTarget == null) throw new ArgumentNullException("dropTarget");
  628.       if (dataDropTarget == null) dataDropTarget = BuildDefaultTarget(dropTarget);
  629.  
  630.       _dropTarget = dropTarget;
  631.       _dataDropTarget = dataDropTarget;
  632.       _hilighter = targetHilighter;
  633.  
  634.       _dropTarget.AllowDrop = true;
  635.       _dropTarget.DragEnter += DropTarget_DragEnter;
  636.       _dropTarget.DragOver += DropTarget_DragOver;
  637.       _dropTarget.Drop += DropTarget_Drop;
  638.       _dropTarget.DragLeave += DropTarget_DragLeave;
  639.    }
  640.  
  641.    protected UIElement DropTarget
  642.    {
  643.       get { return _dropTarget; }
  644.    }
  645.  
  646.    protected IDataDropTarget DataDropTarget
  647.    {
  648.       get { return _dataDropTarget; }
  649.    }
  650.  
  651.    protected IDropTargetHilighter TargetHilighter
  652.    {
  653.       get { return _hilighter ?? _defaultHilighter; }
  654.    }
  655.  
  656.    public DragDropEffects AllowedEffects
  657.    {
  658.       get { return _allowedEffects; }
  659.       set { _allowedEffects = value; }
  660.    }
  661.  
  662.    public string[] AllowedDataTypes
  663.    {
  664.       get { return _allowedDataTypes ?? DefaultDataTypes; }
  665.       set { _allowedDataTypes = value; }
  666.    }
  667.  
  668.    private void DropTarget_DragEnter(object sender, DragEventArgs e)
  669.    {
  670.       if (CanDrop(e))
  671.       {
  672.          AddTargetHilight();
  673.       }
  674.    }
  675.  
  676.    private void DropTarget_DragLeave(object sender, DragEventArgs e)
  677.    {
  678.       RemoveTargetHilight();
  679.    }
  680.  
  681.    private void DropTarget_DragOver(object sender, DragEventArgs e)
  682.    {
  683.       if (CanDrop(e))
  684.       {
  685.          if (e.Effects == DragDropEffects.None)
  686.          {
  687.             e.Effects = AllowedEffects;
  688.          }
  689.       }
  690.       else
  691.       {
  692.          e.Effects = DragDropEffects.None;
  693.       }
  694.  
  695.       e.Handled = true;
  696.    }
  697.  
  698.    private void DropTarget_Drop(object sender, DragEventArgs e)
  699.    {
  700.       Drop(e);
  701.    }
  702.  
  703.    protected virtual void AddTargetHilight()
  704.    {
  705.       _hilighterState = TargetHilighter.AddHilight(DropTarget);
  706.    }
  707.  
  708.    protected virtual void RemoveTargetHilight()
  709.    {
  710.       try
  711.       {
  712.          TargetHilighter.RemoveHilight(DropTarget, _hilighterState);
  713.       }
  714.       finally
  715.       {
  716.          var state = _hilighterState as IDisposable;
  717.          if (state != null) state.Dispose();
  718.          _hilighterState = null;
  719.       }
  720.    }
  721.  
  722.    protected virtual bool CanDrop(DragEventArgs args)
  723.    {
  724.       if (args == null) throw new ArgumentNullException("args");
  725.       if (args.Data == null) throw new ArgumentException("No data.", "args");
  726.  
  727.       bool result = false;
  728.  
  729.       IDataObject data = args.Data;
  730.       string[] types = data.GetFormats();
  731.       string[] allowedTypes = AllowedDataTypes;
  732.       if (types != null && types.Length != 0 && allowedTypes != null && allowedTypes.Length != 0)
  733.       {
  734.          if (allowedTypes.Length == 1 && allowedTypes[0] == "*")
  735.          {
  736.             result = true;
  737.          }
  738.          else if (types.Intersect(allowedTypes, StringComparer.OrdinalIgnoreCase).Any())
  739.          {
  740.             result = true;
  741.          }
  742.       }
  743.       if (result && _dataDropTarget != null)
  744.       {
  745.          if (data.GetDataPresent(DragDataWrapperKey))
  746.          {
  747.             var wrapper = data.GetData(DragDataWrapperKey) as DragDataWrapper;
  748.             if (wrapper != null && wrapper.Shim != null)
  749.             {
  750.                if ((DragDropProviderActions.Data & wrapper.Shim.SupportedActions) == DragDropProviderActions.Data)
  751.                {
  752.                   result = _dataDropTarget.CanDrop(args, wrapper.Data);
  753.                }
  754.             }
  755.          }
  756.       }
  757.  
  758.       return result;
  759.    }
  760.  
  761.    protected virtual void Drop(DragEventArgs args)
  762.    {
  763.       if (args == null) throw new ArgumentNullException("args");
  764.       if (args.Data == null) throw new ArgumentException("No data.", "args");
  765.  
  766.       IDataObject data = args.Data;
  767.  
  768.       bool isDataOperation = false;
  769.       DragDataWrapper wrapper = null;
  770.       if (data.GetDataPresent(DragDataWrapperKey))
  771.       {
  772.          wrapper = data.GetData(DragDataWrapperKey) as DragDataWrapper;
  773.          if (wrapper != null && wrapper.Shim != null)
  774.          {
  775.             isDataOperation = (DragDropProviderActions.Data & wrapper.Shim.SupportedActions) == DragDropProviderActions.Data;
  776.          }
  777.       }
  778.  
  779.       if (isDataOperation)
  780.       {
  781.          if (_dataDropTarget != null)
  782.          {
  783.             _dataDropTarget.DataDropped(args, wrapper.Data);
  784.          }
  785.       }
  786.       else
  787.       {
  788.          if (data.GetDataPresent(UIElementKey))
  789.          {
  790.             bool unparented = false;
  791.             var element = (UIElement)data.GetData(UIElementKey);
  792.             if (args.AllowedEffects == DragDropEffects.Move)
  793.             {
  794.                unparented = Unparent(wrapper, element);
  795.             }
  796.             if (unparented)
  797.             {
  798.                Panel panel;
  799.                ContentControl contentControl;
  800.                ItemsControl itemsControl;
  801.  
  802.                if ((panel = _dropTarget as Panel) != null)
  803.                {
  804.                   panel.Children.Add(element);
  805.                }
  806.                else if ((contentControl = _dropTarget as ContentControl) != null)
  807.                {
  808.                   contentControl.Content = element;
  809.                }
  810.                else if ((itemsControl = _dropTarget as ItemsControl) != null)
  811.                {
  812.                   if (itemsControl.ItemsSource == null)
  813.                   {
  814.                      itemsControl.Items.Insert(0, element);
  815.                   }
  816.                }
  817.             }
  818.          }
  819.          else if (data.GetDataPresent(DataFormats.Text))
  820.          {
  821.             var value = (string)data.GetData(DataFormats.Text);
  822.  
  823.             Panel panel;
  824.             ContentControl contentControl;
  825.             ItemsControl itemsControl;
  826.  
  827.             if ((panel = _dropTarget as Panel) != null)
  828.             {
  829.                panel.Children.Add(new TextBlock
  830.                {
  831.                   Text = value,
  832.                   FontSize = 16,
  833.                   TextWrapping = TextWrapping.Wrap,
  834.                   MaxWidth = panel.ActualWidth
  835.                });
  836.             }
  837.             else if ((contentControl = _dropTarget as ContentControl) != null)
  838.             {
  839.                contentControl.Content = value;
  840.             }
  841.             else if ((itemsControl = _dropTarget as ItemsControl) != null)
  842.             {
  843.                if (itemsControl.ItemsSource == null)
  844.                {
  845.                   itemsControl.Items.Insert(0, value);
  846.                }
  847.             }
  848.          }
  849.       }
  850.  
  851.       RemoveTargetHilight();
  852.    }
  853.  
  854.    private static bool Unparent(DragDataWrapper wrapper, UIElement element)
  855.    {
  856.       bool success = false;
  857.       if (wrapper != null && wrapper.Shim != null && wrapper.AllowChildrenRemove)
  858.       {
  859.          success = wrapper.Shim.UnParent();
  860.       }
  861.       if (!success) // BRUTE FORCE
  862.       {
  863.          var frameworkElement = element as FrameworkElement;
  864.          if (frameworkElement != null && frameworkElement.Parent != null)
  865.          {
  866.             Panel parentPanel;
  867.             ContentControl parentContent;
  868.             ItemsControl parentItems;
  869.  
  870.             if ((parentPanel = frameworkElement.Parent as Panel) != null)
  871.             {
  872.                parentPanel.Children.Remove(element);
  873.                success = true;
  874.             }
  875.             else if ((parentContent = frameworkElement.Parent as ContentControl) != null)
  876.             {
  877.                parentContent.Content = null;
  878.                success = true;
  879.             }
  880.             else if ((parentItems = frameworkElement.Parent as ItemsControl) != null)
  881.             {
  882.                if (parentItems.ItemsSource != null)
  883.                {
  884.                   int index = parentItems.ItemContainerGenerator.IndexFromContainer(element);
  885.                   if (index != -1)
  886.                   {
  887.                      parentItems.Items.RemoveAt(index);
  888.                      success = true;
  889.                   }
  890.                }
  891.             }
  892.          }
  893.       }
  894.  
  895.       return success;
  896.    }
  897.  
  898.    private static IDataDropTarget BuildDefaultTarget(UIElement dropTarget)
  899.    {
  900.       var target = dropTarget as IDataDropTarget;
  901.       if (target != null) return target;
  902.  
  903.       var list = dropTarget as ItemsControl;
  904.       if (list != null) return new ListBoxDataDropTarget(list);
  905.  
  906.       var contentControl = dropTarget as ContentControl;
  907.       if (contentControl != null) return new ContentControlDropTarget(contentControl);
  908.  
  909.       return null;
  910.    }
  911. }
  912.  
  913. public sealed class ContentControlDropTarget : IDataDropTarget
  914. {
  915.    private readonly ContentControl _control;
  916.  
  917.    public ContentControlDropTarget(ContentControl control)
  918.    {
  919.       if (control == null) throw new ArgumentNullException("control");
  920.       _control = control;
  921.    }
  922.  
  923.    public bool CanDrop(DragEventArgs args, object rawData)
  924.    {
  925.       return true;
  926.    }
  927.  
  928.    public void DataDropped(DragEventArgs args, object rawData)
  929.    {
  930.       _control.Content = rawData;
  931.    }
  932. }
  933.  
  934. public class ListBoxDataDropTarget : IDataDropTarget
  935. {
  936.    private readonly ItemsControl _control;
  937.  
  938.    public ListBoxDataDropTarget(ItemsControl control)
  939.    {
  940.       if (control == null) throw new ArgumentNullException("control");
  941.       _control = control;
  942.    }
  943.  
  944.    public bool CanDrop(DragEventArgs args, object rawData)
  945.    {
  946.       var list = _control.ItemsSource as IList ?? _control.Items;
  947.       return list != null && !list.Contains(rawData);
  948.    }
  949.  
  950.    public void DataDropped(DragEventArgs args, object rawData)
  951.    {
  952.       var list = _control.ItemsSource as IList ?? _control.Items;
  953.  
  954.       if (list == null || !AddItem(list, rawData))
  955.       {
  956.          if (args != null)
  957.          {
  958.             args.Effects = DragDropEffects.None;
  959.          }
  960.       }
  961.    }
  962.  
  963.    protected virtual bool AddItem(IList items, object itemToAdd)
  964.    {
  965.       if (items == null || itemToAdd == null) return false;
  966.  
  967.       bool result = !items.Contains(itemToAdd);
  968.       if (result) items.Add(itemToAdd);
  969.       return result;
  970.    }
  971. }
  972.  
  973. public class ListBoxDragDropDataProvider : IDataDropObjectProvider
  974. {
  975.    private readonly Selector _control;
  976.  
  977.    public ListBoxDragDropDataProvider(Selector control)
  978.    {
  979.       if (control == null) throw new ArgumentNullException("control");
  980.       _control = control;
  981.    }
  982.  
  983.    public DragDropProviderActions SupportedActions
  984.    {
  985.       get { return DragDropProviderActions.Data | DragDropProviderActions.MultiFormatData | DragDropProviderActions.Visual | DragDropProviderActions.Unparent; }
  986.    }
  987.  
  988.    public object GetData()
  989.    {
  990.       return _control.SelectedItem;
  991.    }
  992.  
  993.    public void AppendData(ref IDataObject data, MouseEventArgs e)
  994.    {
  995.       if (data == null) throw new ArgumentNullException("data");
  996.  
  997.       object value = _control.SelectedItem;
  998.       if (value != null)
  999.       {
  1000.          data.SetData(value.GetType().ToString(), value);
  1001.  
  1002.          var element = value as XmlElement;
  1003.          if (element != null)
  1004.          {
  1005.             data.SetData(DataFormats.Text, element.OuterXml);
  1006.          }
  1007.          else if (!(value is string))
  1008.          {
  1009.             data.SetData(DataFormats.Text, value.ToString());
  1010.          }
  1011.       }
  1012.    }
  1013.  
  1014.    public UIElement GetVisual(MouseEventArgs e)
  1015.    {
  1016.       object value = _control.SelectedItem;
  1017.       return value == null ? null : _control.ItemContainerGenerator.ContainerFromItem(value) as UIElement;
  1018.    }
  1019.  
  1020.    protected virtual void GiveFeedback(GiveFeedbackEventArgs args)
  1021.    {
  1022.       throw new NotSupportedException();
  1023.    }
  1024.  
  1025.    void IDataDropObjectProvider.GiveFeedback(GiveFeedbackEventArgs args)
  1026.    {
  1027.       GiveFeedback(args);
  1028.    }
  1029.  
  1030.    protected virtual void ContinueDrag(QueryContinueDragEventArgs args)
  1031.    {
  1032.       throw new NotSupportedException();
  1033.    }
  1034.  
  1035.    void IDataDropObjectProvider.ContinueDrag(QueryContinueDragEventArgs args)
  1036.    {
  1037.       ContinueDrag(args);
  1038.    }
  1039.  
  1040.    protected virtual bool UnParent()
  1041.    {
  1042.       throw new NotSupportedException();
  1043.    }
  1044.  
  1045.    bool IDataDropObjectProvider.UnParent()
  1046.    {
  1047.       return UnParent();
  1048.    }
  1049. }
  1050.  
  1051. public interface ICommandExecutor
  1052. {
  1053.    bool? CanExecute(ICommand command, object parameter);
  1054.    void Execute(ICommand command, object parameter);
  1055. }
  1056.  
  1057. public class CommandDataDropTarget : IDataDropTarget
  1058. {
  1059.    private readonly ICommand _dropCommand;
  1060.    private readonly object _dropCommandParameter;
  1061.  
  1062.    public CommandDataDropTarget(ICommand dropCommand, object dropCommandParameter = null)
  1063.    {
  1064.       if (dropCommand == null) throw new ArgumentNullException("dropCommand");
  1065.  
  1066.       _dropCommand = dropCommand;
  1067.       _dropCommandParameter = dropCommandParameter;
  1068.    }
  1069.  
  1070.    public ICommand DropCommand
  1071.    {
  1072.       get { return _dropCommand; }
  1073.    }
  1074.  
  1075.    public object DropCommandParameter
  1076.    {
  1077.       get { return _dropCommandParameter; }
  1078.    }
  1079.  
  1080.    public bool CanDrop(DragEventArgs args, object rawData)
  1081.    {
  1082.       var executor = rawData as ICommandExecutor;
  1083.       return executor != null && executor.CanExecute(_dropCommand, _dropCommandParameter).GetValueOrDefault();
  1084.    }
  1085.  
  1086.    public void DataDropped(DragEventArgs args, object rawData)
  1087.    {
  1088.       var executor = rawData as ICommandExecutor;
  1089.       if (executor != null)
  1090.       {
  1091.          Action<ICommand, object> method = executor.Execute;
  1092.          Dispatcher.CurrentDispatcher.BeginInvoke(method, DispatcherPriority.DataBind, _dropCommand, _dropCommandParameter);
  1093.       }
  1094.    }
  1095. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement