Reorder ItemsControl with Drag and Drop using MVVM

KrisTrip picture KrisTrip · Jun 28, 2011 · Viewed 9.6k times · Source

I recently asked a question on how to reorder an ItemsControl using Drag and Drop (ItemsControl Drag and Drop). The answer worked great for the time being (code below) but now I am trying to implement MVVM and the current solution requires access to items in the view. Any ideas how to change this to work with MVVM? I plan to make attached properties to bind to commands but I don't know how to get rid of lines such as: int index = (int)(e.GetPosition(DimsContainer).X / width);

Current drag and drop code:

private void DimsContainer_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isDown = true;
        _startPoint = e.GetPosition(this.DimsContainer);
    }

    private void DimsContainer_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _isDown = false;
        _isDragging = false;

        if (_realDragSource != null)
        {
            _realDragSource.ReleaseMouseCapture();
        }
    }

    private void DimsContainer_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (_isDown)
        {
            if ((_isDragging == false) &&
                ((Math.Abs(e.GetPosition(this.DimsContainer).X - _startPoint.X) >
                    SystemParameters.MinimumHorizontalDragDistance) ||
                 (Math.Abs(e.GetPosition(this.DimsContainer).Y - _startPoint.Y) >
                    SystemParameters.MinimumVerticalDragDistance)))
            {
                _isDragging = true;
                _realDragSource = e.Source as UIElement;
                _realDragSource.CaptureMouse();

                double width = ((FrameworkElement)(this.DimsContainer.ItemContainerGenerator.ContainerFromIndex(0))).ActualWidth;
                int index = (int)(e.GetPosition(DimsContainer).X / width);
                DragDrop.DoDragDrop(_realDragSource, new DataObject("UIElement", index, true), DragDropEffects.Move);
            }
        }
    }

    private void DimsContainer_DragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("UIElement"))
        {
            e.Effects = DragDropEffects.Move;
        }
    }

    private void DimsContainer_Drop(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("UIElement"))
        {
            int sourceIndex = (int)e.Data.GetData("UIElement");
            int removedObject = this.indices[sourceIndex];
            this.indices.RemoveAt(sourceIndex);

            UIElement droptarget = e.Source as UIElement;

            // If a drag/drop is happening, there is definitely
            // one child in the DimsContainer
            double width = ((FrameworkElement)(this.DimsContainer.ItemContainerGenerator.ContainerFromIndex(0))).ActualWidth;
            int index = (int)(e.GetPosition(DimsContainer).X / width);

            try
            {
                this.indices.Insert(index, removedObject);
            }
            catch (InvalidOperationException)
            {
                // ignore
            }

            _isDown = false;
            _isDragging = false;
            _realDragSource.ReleaseMouseCapture();
        }
    }

    public static int RemoveItemFromItemsControl(ItemsControl itemsControl, object itemToRemove)
    {
        int indexToBeRemoved = -1;
        if (itemToRemove != null)
        {
            indexToBeRemoved = itemsControl.Items.IndexOf(itemToRemove);

            if (indexToBeRemoved != -1)
            {
                IEnumerable itemsSource = itemsControl.ItemsSource;
                if (itemsSource == null)
                {
                    itemsControl.Items.RemoveAt(indexToBeRemoved);
                }
                // Is the ItemsSource IList or IList<T>? If so, remove the item from the list.
                else if (itemsSource is IList)
                {
                    ((IList)itemsSource).RemoveAt(indexToBeRemoved);
                }
                else
                {
                    Type type = itemsSource.GetType();
                    Type genericIListType = type.GetInterface("IList`1");
                    if (genericIListType != null)
                    {
                        type.GetMethod("RemoveAt").Invoke(itemsSource, new object[] { indexToBeRemoved });
                    }
                }
            }
        }
        return indexToBeRemoved;
    }

    public static void InsertItemInItemsControl(ItemsControl itemsControl, object itemToInsert, int insertionIndex)
    {
        if (itemToInsert != null)
        {
            IEnumerable itemsSource = itemsControl.ItemsSource;

            if (itemsSource == null)
            {
                itemsControl.Items.Insert(insertionIndex, itemToInsert);
            }
            // Is the ItemsSource IList or IList<T>? If so, insert the dragged item in the list.
            else if (itemsSource is IList)
            {
                ((IList)itemsSource).Insert(insertionIndex, itemToInsert);
            }
            else
            {
                Type type = itemsSource.GetType();
                Type genericIListType = type.GetInterface("IList`1");
                if (genericIListType != null)
                {
                    type.GetMethod("Insert").Invoke(itemsSource, new object[] { insertionIndex, itemToInsert });
                }
            }
        }
    }

Answer

user819313 picture user819313 · Jun 28, 2011