aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Android_Studio/Tango.UnitTesting/src/main/AndroidManifest.xml
blob: 89fc2427a85d0143903a18419dcaf25ecef52802 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.twine.tango.unittesting">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Tango.Core;
using Tango.Core.EventArguments;
using Tango.Logging;

namespace Tango.DragAndDrop
{
    /// <summary>
    /// Represents a drag and drop service which exposes several attached properties and events to create an interactive drag and drop functionality.
    /// </summary>
    /// <seealso cref="DraggingSurface" />
    /// <seealso cref="DropEventArgs" />
    public static class DragAndDropService
    {
        private static WeakList<FrameworkElement> _dragElements;
        private static WeakList<FrameworkElement> _dropElements;
        private static Point _mouseDownLocation;
        private static FrameworkElement _currentDragedElement;
        private static FrameworkElement _currentDropElement;
        private static bool _isMouseDown;
        private static DispatcherTimer _dragTimer;
        private static Border _dragBorder;
        private static TouchDevice _touchDevice;
        //private const int MIN_DRAG_OFFSET = 8;

        #region Events

        public static event EventHandler<FrameworkElement> DragStarted;
        public static event EventHandler<FrameworkElement> DragEnded;

        #endregion

        #region Delegates

        /// <summary>
        /// Represents the attached <see cref="DropEvent"/> event delegate.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DropEventArgs"/> instance containing the event data.</param>
        public delegate void DropEventHandler(object sender, DropEventArgs e);

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes the <see cref="DragAndDropService"/> class.
        /// </summary>
        static DragAndDropService()
        {
            _dragElements = new WeakList<FrameworkElement>();
            _dropElements = new WeakList<FrameworkElement>();
            _dragTimer = new DispatcherTimer();
            _dragTimer.Interval = TimeSpan.FromMilliseconds(30);
            _dragTimer.Tick += DragTimer_Tick;
            _dragTimer.IsEnabled = false;
        }

        #endregion

        #region Attached Properties

        #region MinDragOffset

        /// <summary>
        /// Determines whether an element is MinDragOffset by the drag and drop service.
        /// </summary>
        public static readonly DependencyProperty MinDragOffsetProperty =
            DependencyProperty.RegisterAttached("MinDragOffset",
            typeof(int), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(8));
        /// <summary>
        /// Sets the MinDragOffset attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetMinDragOffset(FrameworkElement element, int value)
        {
            element.SetValue(MinDragOffsetProperty, value);
        }

        /// <summary>
        /// Gets the MinDragOffset attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static int GetMinDragOffset(FrameworkElement element)
        {
            return (int)element.GetValue(MinDragOffsetProperty);
        }

        #endregion

        #region DropCommand

        /// <summary>
        /// Determines whether an element is DropCommand by the drag and drop service.
        /// </summary>
        public static readonly DependencyProperty DropCommandProperty =
            DependencyProperty.RegisterAttached("DropCommand",
            typeof(ICommand), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(null));
        /// <summary>
        /// Sets the DropCommand attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetDropCommand(FrameworkElement element, ICommand value)
        {
            element.SetValue(DropCommandProperty, value);
        }

        /// <summary>
        /// Gets the DropCommand attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static ICommand GetDropCommand(FrameworkElement element)
        {
            return (ICommand)element.GetValue(DropCommandProperty);
        }

        #endregion

        #region Draggable

        /// <summary>
        /// Determines whether an element is draggable by the drag and drop service.
        /// </summary>
        public static readonly DependencyProperty DraggableProperty =
            DependencyProperty.RegisterAttached("Draggable",
            typeof(bool), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(false, DraggableChanged));

        /// <summary>
        /// Draggable changed.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void DraggableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                RegisterDraggable(d as FrameworkElement);
            }
            else
            {
                UnRegisterDraggable(d as FrameworkElement);
            }
        }

        /// <summary>
        /// Sets the draggable attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetDraggable(FrameworkElement element, bool value)
        {
            element.SetValue(DraggableProperty, value);
        }

        /// <summary>
        /// Gets the draggable attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static bool GetDraggable(FrameworkElement element)
        {
            return (bool)element.GetValue(DraggableProperty);
        }

        #endregion

        #region IsDragging

        /// <summary>
        /// Determines whether the draggable element is currently being dragged.
        /// </summary>
        public static readonly DependencyProperty IsDraggingProperty =
            DependencyProperty.RegisterAttached("IsDragging",
            typeof(bool), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(false));

        /// <summary>
        /// Sets the IsDragging attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetIsDragging(FrameworkElement element, bool value)
        {
            element.SetValue(IsDraggingProperty, value);
        }

        /// <summary>
        /// Gets the is dragging attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static bool GetIsDragging(FrameworkElement element)
        {
            return (bool)element.GetValue(IsDraggingProperty);
        }

        #endregion

        #region DraggableBackground

        /// <summary>
        /// Determines the draggable element replication background.
        /// </summary>
        public static readonly DependencyProperty DraggableBackgroundProperty =
            DependencyProperty.RegisterAttached("DraggableBackground",
            typeof(Brush), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(null));

        /// <summary>
        /// Sets the draggable background attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        public static void SetDraggableBackground(FrameworkElement element, Brush value)
        {
            element.SetValue(DraggableBackgroundProperty, value);
        }

        /// <summary>
        /// Gets the draggable background attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static Brush GetDraggableBackground(FrameworkElement element)
        {
            return (Brush)element.GetValue(DraggableBackgroundProperty);
        }

        #endregion

        #region DraggableBorderBrush

        /// <summary>
        /// Determines the draggable element replication border brush.
        /// </summary>
        public static readonly DependencyProperty DraggableBorderBrushProperty =
            DependencyProperty.RegisterAttached("DraggableBorderBrush",
            typeof(Brush), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(null));

        /// <summary>
        /// Sets the draggable border brush attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        public static void SetDraggableBorderBrush(FrameworkElement element, Brush value)
        {
            element.SetValue(DraggableBorderBrushProperty, value);
        }

        /// <summary>
        /// Gets the draggable border brush attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static Brush GetDraggableBorderBrush(FrameworkElement element)
        {
            return (Brush)element.GetValue(DraggableBorderBrushProperty);
        }

        #endregion

        #region DraggableOpacity

        /// <summary>
        /// Determines the draggable element replication opacity.
        /// </summary>
        public static readonly DependencyProperty DraggableOpacityProperty =
            DependencyProperty.RegisterAttached("DraggableOpacity",
            typeof(double), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(0.8));

        /// <summary>
        /// Sets the draggable opacity attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        public static void SetDraggableOpacity(FrameworkElement element, double value)
        {
            element.SetValue(DraggableOpacityProperty, value);
        }

        /// <summary>
        /// Gets the draggable opacity attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static double GetDraggableOpacity(FrameworkElement element)
        {
            return (double)element.GetValue(DraggableOpacityProperty);
        }

        #endregion

        #region Droppable

        /// <summary>
        /// Determines whether an element is a dropable target by the drag and drop service.
        /// </summary>
        public static readonly DependencyProperty DroppableProperty =
            DependencyProperty.RegisterAttached("Droppable",
            typeof(bool), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(false, DroppableChanged));

        /// <summary>
        /// Droppables the changed attached property.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void DroppableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                RegisterDroppable(d as FrameworkElement);
            }
            else
            {
                UnRegisterDroppable(d as FrameworkElement);
            }
        }

        /// <summary>
        /// Sets the droppable attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetDroppable(FrameworkElement element, bool value)
        {
            element.SetValue(DroppableProperty, value);
        }

        /// <summary>
        /// Gets the droppable attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static bool GetDroppable(FrameworkElement element)
        {
            return (bool)element.GetValue(DroppableProperty);
        }

        #endregion

        #region IsDraggableOver

        /// <summary>
        /// Determines whether a draggable element currently hovers over the droppable element.
        /// </summary>
        public static readonly DependencyProperty IsDraggableOverProperty =
            DependencyProperty.RegisterAttached("IsDraggableOver",
            typeof(bool), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(false));

        /// <summary>
        /// Sets the is draggable over attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetIsDraggableOver(FrameworkElement element, bool value)
        {
            element.SetValue(IsDraggableOverProperty, value);
        }

        /// <summary>
        /// Gets the is draggable over attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static bool GetIsDraggableOver(FrameworkElement element)
        {
            return (bool)element.GetValue(IsDraggableOverProperty);
        }

        #endregion

        #region Dragging Surface

        /// <summary>
        /// Determines the Draggable dragging surface.
        /// </summary>
        public static readonly DependencyProperty DraggingSurfaceProperty =
            DependencyProperty.RegisterAttached("DraggingSurface",
            typeof(DraggingSurface), typeof(DragAndDropService),
            new FrameworkPropertyMetadata(null, DraggingSurfaceChanged));

        /// <summary>
        /// Dragging the surface changed.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void DraggingSurfaceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }

        /// <summary>
        /// Sets the dragging surface attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">The value.</param>
        public static void SetDraggingSurface(FrameworkElement element, DraggingSurface value)
        {
            element.SetValue(DraggingSurfaceProperty, value);
        }

        /// <summary>
        /// Gets the dragging surface attached property.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static DraggingSurface GetDraggingSurface(FrameworkElement element)
        {
            return (DraggingSurface)element.GetValue(DraggingSurfaceProperty);
        }

        #endregion

        #endregion

        #region Attached Events

        /// <summary>
        /// Occurs when a successful drop has occurred. 
        /// </summary>
        public static readonly RoutedEvent DropEvent =
            EventManager.RegisterRoutedEvent("Drop",
                                            RoutingStrategy.Bubble,
                                            typeof(DropEventHandler),
                                            typeof(DragAndDropService));

        /// <summary>
        /// Adds the drop event handler.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <param name="handler">The handler.</param>
        public static void AddDropHandler(DependencyObject o, DropEventHandler handler)
        {
            ((UIElement)o).AddHandler(DropEvent, handler);
        }

        /// <summary>
        /// Removes the drop event handler.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <param name="handler">The handler.</param>
        public static void RemoveDropHandler(DependencyObject o, DropEventHandler handler)
        {
            ((UIElement)o).RemoveHandler(DropEvent, handler);
        }

        #endregion

        #region Drag Timer

        /// <summary>
        /// Handles the Tick event of the DragTimer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private static void DragTimer_Tick(object sender, EventArgs e)
        {
            if ((Mouse.LeftButton == MouseButtonState.Pressed || (_touchDevice != null && _touchDevice.IsActive)) && _currentDragedElement != null)
            {
                DragStarted?.Invoke(_currentDragedElement, _currentDragedElement);

                var surface = GetDraggingSurface(_currentDragedElement);
                var rootElement = surface.Parent as FrameworkElement;

                if (_touchDevice != null)
                {
                    DraggingSurface.SetLeft(_dragBorder, _touchDevice.GetTouchPoint(surface).Position.X - _mouseDownLocation.X);
                    DraggingSurface.SetTop(_dragBorder, _touchDevice.GetTouchPoint(surface).Position.Y - _mouseDownLocation.Y);
                }
                else
                {
                    DraggingSurface.SetLeft(_dragBorder, Mouse.GetPosition(surface).X - _mouseDownLocation.X);
                    DraggingSurface.SetTop(_dragBorder, Mouse.GetPosition(surface).Y - _mouseDownLocation.Y);
                }

                _dragBorder.Visibility = Visibility.Visible;

                bool found = false;

                foreach (var dropElement in _dropElements.Where(x => x != null && x != _currentDragedElement))
                {
                    if (!dropElement.IsLoaded)
                    {
                        dropElement.UpdateLayout();
                        dropElement.InvalidateArrange();
                        dropElement.InvalidateMeasure();
                        dropElement.InvalidateVisual();
                        continue;
                    }

                    //Point dropPoint = dropElement.TransformToAncestor(rootElement).Transform(new Point(0, 0));
                    Point dropPoint = dropElement.PointToScreen(new Point(0, 0));
                    var dropElementScaledSize = dropElement.PointToScreen(new Point(dropElement.ActualWidth, dropElement.ActualHeight)) - dropElement.PointToScreen(new Point(0, 0));
                    Rect dropRect = new Rect(dropPoint, new Size(dropElementScaledSize.X, dropElementScaledSize.Y));
                    Rect dragRect = new Rect(Canvas.GetLeft(_dragBorder), Canvas.GetTop(_dragBorder), _dragBorder.Width / 2, _dragBorder.Height);

                    Point mousePoint = new Point();

                    if (_touchDevice != null)
                    {
                        mousePoint = rootElement.PointToScreen(_touchDevice.GetTouchPoint(rootElement).Position);
                    }
                    else
                    {
                        mousePoint = rootElement.PointToScreen(Mouse.GetPosition(rootElement));
                    }

                    if (dropRect.IntersectsWith(new Rect(mousePoint, new Size(1, 1))))
                    {
                        SetIsDraggableOver(dropElement, true);

                        foreach (var drop in _dropElements.Where(x => x != null && x != dropElement))
                        {
                            SetIsDraggableOver(drop, false);
                        }

                        _currentDropElement = dropElement;
                        found = true;
                    }
                    else
                    {
                        SetIsDraggableOver(dropElement, false);
                    }
                }

                if (!found)
                {
                    _currentDropElement = null;
                }
            }
            else
            {
                DragEnded?.Invoke(_currentDragedElement, _currentDragedElement);
                try
                {
                    DropDraggable();
                }
                catch (Exception ex)
                {
                    LogManager.Default.Log(ex, "Error on drop draggable.");
                }
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Registers a framework element as a draggable element.
        /// </summary>
        /// <param name="element">The element.</param>
        private static void RegisterDraggable(FrameworkElement element)
        {
            foreach (var item in _dragElements.ToList())
            {
                if (item == null)
                {
                    _dragElements.Remove(item);
                }
            }

            if (!_dragElements.Contains(element))
            {
                _dragElements.Add(element);

                element.RegisterForPreviewMouseOrTouchDown(Draggable_PreviewMouseDown);
                element.RegisterForMouseOrTouchMove(Draggable_MouseMove);
                //element.PreviewMouseUp += Draggable_PreviewMouseUp;
                element.AddHandler(FrameworkElement.PreviewMouseUpEvent, new MouseButtonEventHandler(Draggable_PreviewMouseUp));
                //element.IsManipulationEnabled = true;

                //element.AddHandler(FrameworkElement.PreviewMouseDownEvent, (MouseButtonEventHandler)Draggable_PreviewMouseDown, true);
                //element.AddHandler(FrameworkElement.MouseMoveEvent, (MouseEventHandler)Draggable_MouseMove, true);
                //element.AddHandler(FrameworkElement.PreviewMouseUpEvent, (MouseButtonEventHandler)Draggable_PreviewMouseUp, true);
                //element.Unloaded += Draggable_Unloaded;
            }
        }

        /// <summary>
        /// Unregisters a framework element as a draggable element.
        /// </summary>
        /// <param name="element">The element.</param>
        private static void RegisterDroppable(FrameworkElement element)
        {
            foreach (var item in _dropElements.ToList())
            {
                if (item == null)
                {
                    _dropElements.Remove(item);
                }
            }

            if (!_dropElements.Contains(element))
            {
                _dropElements.Add(element);
                //element.Unloaded += Droppable_Unloaded;
            }
        }

        /// <summary>
        /// Handles the Unloaded event of the Element control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
        private static void Draggable_Unloaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            UnRegisterDraggable(element);
        }

        /// <summary>
        /// Handles the Unloaded1 event of the Element control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
        private static void Droppable_Unloaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            UnRegisterDroppable(element);
        }

        /// <summary>
        /// Registers a framework element as a droppable element.
        /// </summary>
        /// <param name="element">The element.</param>
        private static void UnRegisterDraggable(FrameworkElement element)
        {
            _dragElements.Remove(element);
            element.PreviewMouseUp -= Draggable_PreviewMouseUp;
            element.Unloaded -= Draggable_Unloaded;
        }

        /// <summary>
        /// Unregisters a framework element as a droppable element.
        /// </summary>
        /// <param name="element">The element.</param>
        private static void UnRegisterDroppable(FrameworkElement element)
        {
            _dropElements.Remove(element);
            element.Unloaded -= Droppable_Unloaded;
        }

        /// <summary>
        /// Creates the dragging element replication.
        /// </summary>
        private static void CreateDraggingElement()
        {
            if (_currentDragedElement != null)
            {
                BitmapSource source = _currentDragedElement.TakeSnapshot();
                _dragBorder = new Border();

                var surface = GetDraggingSurface(_currentDragedElement);

                _dragBorder.Background = GetDraggableBackground(_currentDragedElement);
                _dragBorder.BorderThickness = new Thickness(1);
                _dragBorder.BorderBrush = GetDraggableBorderBrush(_currentDragedElement);
                //dragBorder.CornerRadius = new CornerRadius(currentDragedElement.BorderRadius);

                _dragBorder.Visibility = Visibility.Hidden;
                _dragBorder.IsHitTestVisible = false;
                _dragBorder.Width = source.PixelWidth;
                _dragBorder.Height = source.PixelHeight;
                _dragBorder.Opacity = GetDraggableOpacity(_currentDragedElement);

                Image img = new Image();
                _dragBorder.Child = img;
                img.Stretch = System.Windows.Media.Stretch.Fill;
                img.Source = source;

                ScaleTransform scale = new ScaleTransform(1, 1, 0.5, 0.5);
                _dragBorder.RenderTransformOrigin = new Point(0.5, 0.5);
                _dragBorder.RenderTransform = scale;
                surface.Children.Add(_dragBorder);

                DoubleAnimation ani = new DoubleAnimation(0.95, new Duration(TimeSpan.FromMilliseconds(300)));
                ani.AutoReverse = true;
                ani.RepeatBehavior = RepeatBehavior.Forever;

                DoubleAnimation aniOp = new DoubleAnimation(_dragBorder.Opacity, 0.5, new Duration(TimeSpan.FromMilliseconds(300)));
                aniOp.AutoReverse = true;
                aniOp.RepeatBehavior = RepeatBehavior.Forever;

                scale.BeginAnimation(ScaleTransform.ScaleXProperty, ani);
                scale.BeginAnimation(ScaleTransform.ScaleYProperty, ani);
                _dragBorder.BeginAnimation(ContentControl.OpacityProperty, aniOp);
            }
        }

        /// <summary>
        /// Removes the dragging element replication.
        /// </summary>
        private static void RemoveDraggingElement()
        {
            if (_dragBorder != null)
            {
                _dragBorder.RenderTransform.BeginAnimation(ScaleTransform.ScaleXProperty, null);
                _dragBorder.RenderTransform.BeginAnimation(ScaleTransform.ScaleYProperty, null);
                _dragBorder.BeginAnimation(ContentControl.OpacityProperty, null);
            }

            var surface = GetDraggingSurface(_currentDragedElement);
            surface.Children.Clear();
        }

        /// <summary>
        /// Drops the draggable.
        /// </summary>
        /// <param name="noDrop">if set to <c>true</c> [no drop].</param>
        private static void DropDraggable(bool noDrop = false)
        {
            _isMouseDown = false;
            RemoveDraggingElement();
            _dragTimer.Stop();
            SetIsDragging(_currentDragedElement, false);

            foreach (var dropElement in _dropElements.Where(x => x != null))
            {
                SetIsDraggableOver(dropElement, false);
            }

            if (noDrop)
            {
                _currentDragedElement = null;
                _currentDropElement = null;
                return;
            }

            if (_currentDropElement != null && _currentDragedElement != null)
            {
                _currentDropElement.RaiseEvent(new DropEventArgs(DropEvent, _currentDragedElement, _currentDropElement, _mouseDownLocation));

                var command = GetDropCommand(_currentDropElement);
                if (command != null)
                {
                    command.Execute(new DropEventArgs(DropEvent, _currentDragedElement, _currentDropElement, _mouseDownLocation));
                }

                _currentDragedElement = null;
                _currentDropElement = null;
            }
            else if (_currentDropElement == null && _currentDragedElement != null)
            {
                //if (DroppedNoWhere != null) DroppedNoWhere(this, currentDragedElement.Element);
                //TODO: ??
            }
        }

        #endregion

        #region Draggable Event Handlers

        private static void Draggable_PreviewMouseDown(object sender, MouseOrTouchEventArgs e)
        {
            var dragThumb = (sender as FrameworkElement).FindChild<DragThumb>();

            if ((e.Source != sender && dragThumb == null) || (dragThumb != null && dragThumb != e.OriginalSource))
            {
                _currentDragedElement = null;
                return;
            }

            FrameworkElement element = sender as FrameworkElement;

            if (!_dragElements.Where(x => x != null).ToList().Exists(x => x == element))
            {
                e.Handled = false;
                return;
            }

            _mouseDownLocation = e.GetPosition(element);
            _currentDragedElement = element;
            _isMouseDown = true;
        }



        /// <summary>
        /// Handles the MouseMove event of the Draggable control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
        private static void Draggable_MouseMove(object sender, MouseOrTouchEventArgs e)
        {
            if (_isMouseDown)
            {
                FrameworkElement element = _currentDragedElement;

                if (element != null)
                {
                    int minDragOffset = GetMinDragOffset(element);

                    var surface = GetDraggingSurface(element);

                    if (surface != null)
                    {
                        if ((e.GetPosition(element).X > _mouseDownLocation.X + minDragOffset || e.GetPosition(element).X < _mouseDownLocation.X - minDragOffset) || (e.GetPosition(element).Y > _mouseDownLocation.Y + minDragOffset || e.GetPosition(element).Y < _mouseDownLocation.Y - minDragOffset))
                        {
                            element.ReleaseMouseCapture();
                            surface.ReleaseMouseCapture();

                            if (e.TouchDevice != null)
                            {
                                element.ReleaseTouchCapture(e.TouchDevice);
                                surface.ReleaseTouchCapture(e.TouchDevice);
                            }

                            _isMouseDown = false;
                            CreateDraggingElement();
                            _touchDevice = e.TouchDevice;
                            _dragTimer.Start();
                            SetIsDragging(element, true);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Handles the PreviewMouseUp event of the Draggable control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private static void Draggable_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            FrameworkElement element = _currentDragedElement;

            if (element != null)
            {
                e.Handled = true;

                if ((e.GetPosition(element).X > _mouseDownLocation.X + 10 || e.GetPosition(element).X < _mouseDownLocation.X - 10) || (e.GetPosition(element).Y > _mouseDownLocation.Y + 10 || e.GetPosition(element).Y < _mouseDownLocation.Y - 10))
                {
                    DropDraggable();
                }
                else
                {
                    DropDraggable(true);
                }
            }
        }

        #endregion
    }
}