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 });
}
}
}
}
use drag and drop behavior. e.g. http://www.codeproject.com/KB/WPF/gong-wpf-dragdrop-ii.aspx