/// <summary>
        /// This scrolls the items control when we hit a boundary
        /// </summary>
        /// <param name="itemsControl"></param>
        /// <param name="e"></param>
        private void HandleDragScrolling(ItemsControl itemsControl, DragEventArgs e)
        {
            bool?isMouseAtTop = DragUtilities.IsMousePointerAtTop(itemsControl, e.GetPosition(itemsControl));

            if (isMouseAtTop.HasValue)
            {
                if (this._dragScrollWaitCounter == DragWaitCounterThreshold)
                {
                    this._dragScrollWaitCounter = 0;

                    ScrollViewer scrollViewer = DragUtilities.FindScrollViewer(itemsControl);
                    if (scrollViewer != null && scrollViewer.CanContentScroll &&
                        scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible)
                    {
                        scrollViewer.ScrollToVerticalOffset((isMouseAtTop.Value) ? scrollViewer.VerticalOffset - 1.0 : scrollViewer.VerticalOffset + 1.0);
                        e.Effects = DragDropEffects.Scroll;
                    }
                }
                else
                {
                    this._dragScrollWaitCounter++;
                }
            }
            else
            {
                e.Effects = GetDropEffectType(e.AllowedEffects, e.KeyStates);
            }
        }
 /// <summary>
 /// Update the position of the insertion point marker
 /// </summary>
 /// <param name="itemsControl"></param>
 /// <param name="e"></param>
 private void UpdateInsertAdorner(ItemsControl itemsControl, DragEventArgs e)
 {
     if (this._insertAdorner != null)
     {
         this._insertAdorner.InTopHalf = DragUtilities.IsPointInTopHalf(itemsControl, e);
         this._insertAdorner.InvalidateVisual();
     }
 }
        /// <summary>
        /// Determine the proper insertion index
        /// </summary>
        /// <param name="itemsControl"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        private static int FindInsertionIndex(ItemsControl itemsControl, DragEventArgs e)
        {
            UIElement dropTargetContainer = DragUtilities.GetItemContainerFromPoint(itemsControl, e.GetPosition(itemsControl));

            if (dropTargetContainer != null)
            {
                int index = itemsControl.ItemContainerGenerator.IndexFromContainer(dropTargetContainer);
                return(DragUtilities.IsPointInTopHalf(itemsControl, e) ? index : index + 1);
            }
            return(itemsControl.Items.Count);
        }
        /// <summary>
        /// Drop started
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PreviewDrop(object sender, DragEventArgs e)
        {
            var itemsControl = (ItemsControl)sender;

            this.DestroyAdorners();
            e.Handled = true;
            if (e.Data.GetDataPresent(this.ItemTypeKey))
            {
                int index = FindInsertionIndex(itemsControl, e);

                DragInfo data = e.Data.GetData(this.ItemTypeKey) as DragInfo;
                if (data != null && (!data.AllowOnlySelf || itemsControl == data.Source))
                {
                    var allowedEffects = e.AllowedEffects;
                    if (this.DropInitiated != null)
                    {
                        DragDropEventArgs de = new DragDropEventArgs(data.Source, itemsControl, data.Data, index)
                        {
                            AllowedEffects = allowedEffects
                        };
                        this.DropInitiated(this, de);
                        allowedEffects = de.AllowedEffects;
                        if (de.Cancel)
                        {
                            e.Effects = DragDropEffects.None;
                            return;
                        }
                    }

                    object itemToAdd = data.Data;
                    e.Effects = GetDropEffectType(allowedEffects, e.KeyStates);

                    if (DragUtilities.DoesItemExists(itemsControl, itemToAdd) &&
                        (e.Effects == DragDropEffects.Move ||
                         (e.Effects & DragDropEffects.Move) > 0 && (e.KeyStates & DragDropKeyStates.ControlKey) > 0))
                    {
                        DragUtilities.RemoveItem(itemsControl, itemToAdd);
                        // Recalc our position based on the removal
                        index = FindInsertionIndex(itemsControl, e);
                    }

                    DragUtilities.AddItem(itemsControl, itemToAdd, index);
                    DragUtilities.SelectItem(itemsControl, index);
                }
                else
                {
                    e.Effects = DragDropEffects.None;
                }
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
        }
        /// <summary>
        /// Starts the drag/drop operation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var   itemsControl = (ItemsControl)sender;
            Point p            = e.GetPosition(itemsControl);

            this._data = DragUtilities.GetDataObjectFromItemsControl(itemsControl, p);
            if (this._data != null)
            {
                this._isMouseDown       = true;
                this._dragStartPosition = p;
            }
        }
 /// <summary>
 /// Initialize the insertion point marker
 /// </summary>
 /// <param name="itemsControl"></param>
 /// <param name="e"></param>
 private void InitializeInsertAdorner(ItemsControl itemsControl, DragEventArgs e)
 {
     if (this._insertAdorner == null && this.ShowInsertAdorner)
     {
         UIElement itemContainer = DragUtilities.GetItemContainerFromPoint(itemsControl, e.GetPosition(itemsControl));
         if (itemContainer != null)
         {
             this._insertAdorner = new InsertAdorner(DragUtilities.IsPointInTopHalf(itemsControl, e),
                                                     DragUtilities.IsItemControlOrientationHorizontal(itemsControl),
                                                     itemContainer, AdornerLayer.GetAdornerLayer(itemsControl), itemsControl);
         }
     }
 }
        /// <summary>
        /// New drop target identified
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PreviewDragEnter(object sender, DragEventArgs e)
        {
            e.Handled = true;
            e.Effects = DragDropEffects.None;

            var itemsControl = (ItemsControl)sender;

            // Do not allow if sorted.
            if (!DragUtilities.CanReorderCollectionView(itemsControl))
            {
                return;
            }

            if (e.Data.GetDataPresent(this.ItemTypeKey))
            {
                DragInfo data = e.Data.GetData(this.ItemTypeKey) as DragInfo;
                if (data != null)
                {
                    if (!data.AllowOnlySelf || itemsControl == data.Source)
                    {
                        var allowedEffects = e.AllowedEffects;

                        if (itemsControl == data.Source && !this.AllowSelf)
                        {
                            allowedEffects = DragDropEffects.None;
                        }
                        else if (this.DropEnter != null)
                        {
                            DragDropEventArgs de = new DragDropEventArgs(data.Source, itemsControl, data.Data)
                            {
                                AllowedEffects = allowedEffects
                            };
                            this.DropEnter(this, de);
                            allowedEffects = de.AllowedEffects;
                            if (de.Cancel)
                            {
                                return;
                            }
                        }

                        this.InitializeDragAdorner(itemsControl, data.Data, e.GetPosition(itemsControl));
                        e.Effects = GetDropEffectType(allowedEffects, e.KeyStates);

                        if (e.Effects != DragDropEffects.None)
                        {
                            this.InitializeInsertAdorner(itemsControl, e);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// This starts the drag operation from the given ItemsControl
        /// </summary>
        /// <param name="itemsControl"></param>
        private void DragStarted(ItemsControl itemsControl)
        {
            DragDropEffects allowedEffects = DragDropEffects.Copy | DragDropEffects.Move;

            if (this.DragInitiated != null)
            {
                var dde = new DragDropEventArgs(itemsControl, null, this._data)
                {
                    AllowedEffects = allowedEffects
                };
                this.DragInitiated(this, dde);
                if (dde.Cancel)
                {
                    this.ResetState();
                    return;
                }
                allowedEffects = dde.AllowedEffects;
            }

            UIElement draggedItemContainer = DragUtilities.GetItemContainerFromPoint(itemsControl, this._dragStartPosition);

            this._isDragging = true;

            DataObject dObject = new DataObject(this.ItemTypeKey, new DragInfo {
                Data = this._data, Source = itemsControl, AllowOnlySelf = this.AllowOnlySelf
            });
            DragDropEffects e = DragDrop.DoDragDrop(itemsControl, dObject, allowedEffects);

            if ((e & DragDropEffects.Move) != 0)
            {
                if (draggedItemContainer != null)
                {
                    int dragItemIndex = itemsControl.ItemContainerGenerator.IndexFromContainer(draggedItemContainer);
                    DragUtilities.RemoveItem(itemsControl, dragItemIndex);
                }
                else
                {
                    DragUtilities.RemoveItem(itemsControl, this._data);
                }
            }

            this.ResetState();
        }
        /// <summary>
        /// Display the drag indicator
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (this._isMouseDown)
            {
                var   itemsControl    = (ItemsControl)sender;
                Point currentPosition = e.GetPosition(itemsControl);
                if ((this._isDragging == false) && (Math.Abs(currentPosition.X - this._dragStartPosition.X) > SystemParameters.MinimumHorizontalDragDistance) ||
                    (Math.Abs(currentPosition.Y - this._dragStartPosition.Y) > SystemParameters.MinimumVerticalDragDistance))
                {
                    // Do not allow if sorted and we only allow this element as
                    // the drop target.
                    if (!DragUtilities.CanReorderCollectionView(itemsControl) &&
                        this.AllowOnlySelf)
                    {
                        return;
                    }

                    this.DragStarted(itemsControl);
                }
            }
        }