Hi all, I run the application in tablet device and it works well for mouse event (using pen also) but get exception when using touch.
The exception happened when swapping the data. Maybe I need to add some validation to handle this exception for touch event?
I have added log and generate into C drive, when u copy the exe to tablet, make sure you are running as administrator.
Download Project
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at FM.UI.View.PanelTypicalParameterCustomization_View.DragDropHelper_ItemDropped(Object sender, DragDropEventArgs e)
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index.
Window1.xaml.cs
using System;
using System.IO;
using System.Windows;
namespace Clarity.Demo.GenericDragDrop
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new Window1ViewModel();
DragDropHelper.ItemDropped += DragDropHelper_ItemDropped;
Unloaded += Window1_Unloaded; ;
}
private void Window1_Unloaded(object sender, RoutedEventArgs e)
{
DragDropHelper.ItemDropped -= DragDropHelper_ItemDropped;
}
private void DragDropHelper_ItemDropped(object sender, DragDropEventArgs e)
{
try
{
Window1ViewModel viewModel = DataContext as Window1ViewModel;
//causing exception An ItemsControl is inconsistent with its items source
//viewModel.Persons.RemoveAt(e.DragDataIndex);
//viewModel.Persons.Insert(e.DragDataIndex, e.TargetData as Person);
//viewModel.Persons.RemoveAt(e.TargetDataIndex);
//viewModel.Persons.Insert(e.TargetDataIndex, e.DragData as Person);
Person temp = e.TargetData as Person;
int a = viewModel.Persons.IndexOf(temp);
int b = viewModel.Persons.IndexOf(e.DragData as Person);
viewModel.Persons[a] = viewModel.Persons[b];
viewModel.Persons[b] = temp;
}
catch (Exception exception)
{
File.AppendAllText(@"C:\log.txt", string.Format("DragDropHelper_ItemDropped, exeception message: {0}\n", exception));
}
}
}
}
Window1ViewModel.cs
using System.Collections.ObjectModel;
namespace Clarity.Demo.GenericDragDrop
{
public class Window1ViewModel
{
private ObservableCollection<Person> persons;
public ObservableCollection<Person> Persons
{
get
{
if (persons == null)
{
persons = new ObservableCollection<Person>();
persons.Add(new Person("Mr A"));
persons.Add(new Person("Mr B"));
persons.Add(new Person("Mr C"));
persons.Add(new Person(string.Empty));
persons.Add(new Person(string.Empty));
persons.Add(new Person(string.Empty));
persons.Add(new Person(string.Empty));
}
return persons;
}
}
public Window1ViewModel()
{
Persons.CollectionChanged += Persons_CollectionChanged;
}
private void Persons_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
}
}
}
DragDropHelper.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Clarity.Demo.GenericDragDrop
{
public class DragDropHelper
{
private Point initialPoint;
private Point delta;
private Point scrollTarget;
private object dropTarget;
private object dragData;
private int dropTargetIndex = -1;
private int dragDataIndex = -1;
private DataGrid selectedTarget;
private DataGridRow selectedRow;
private bool adornerCaptured;
private UserControl topWindow;
private Canvas dragDropAdornerLayer;
private DragDropAdornerBase dragDropAdorner;
private static DragDropHelper instance;
private static DragDropHelper Instance
{
get
{
if (instance == null)
{
instance = new DragDropHelper();
}
return instance;
}
}
public static bool GetIsDragSource(DependencyObject obj)
{
return (bool)obj.GetValue(IsDragSourceProperty);
}
public static void SetIsDragSource(DependencyObject obj, bool value)
{
obj.SetValue(IsDragSourceProperty, value);
}
public static UIElement GetDragDropControl(DependencyObject obj)
{
return (UIElement)obj.GetValue(DragDropControlProperty);
}
public static void SetDragDropControl(DependencyObject obj, UIElement value)
{
obj.SetValue(DragDropControlProperty, value);
}
public static string GetAdornerLayer(DependencyObject obj)
{
return (string)obj.GetValue(AdornerLayerProperty);
}
public static void SetAdornerLayer(DependencyObject obj, string value)
{
obj.SetValue(AdornerLayerProperty, value);
}
public static string GetDropTarget(DependencyObject obj)
{
return (string)obj.GetValue(DropTargetProperty);
}
public static void SetDropTarget(DependencyObject obj, string value)
{
obj.SetValue(DropTargetProperty, value);
}
public static readonly DependencyProperty IsDragSourceProperty = DependencyProperty.RegisterAttached("IsDragSource", typeof(bool), typeof(DragDropHelper), new UIPropertyMetadata(false, IsDragSourceChanged));
public static readonly DependencyProperty DragDropControlProperty = DependencyProperty.RegisterAttached("DragDropControl", typeof(UIElement), typeof(DragDropHelper), new UIPropertyMetadata(null));
public static readonly DependencyProperty AdornerLayerProperty = DependencyProperty.RegisterAttached("AdornerLayer", typeof(string), typeof(DragDropHelper), new UIPropertyMetadata(null));
public static readonly DependencyProperty DropTargetProperty = DependencyProperty.RegisterAttached("DropTarget", typeof(string), typeof(DragDropHelper), new UIPropertyMetadata(string.Empty));
public static event EventHandler<DragDropEventArgs> ItemDropped;
private static void IsDragSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dragSource = d as UIElement;
if (dragSource != null)
{
dragSource.PreviewMouseLeftButtonDown += Instance.DragSource_PreviewMouseLeftButtonDown;
dragSource.PreviewMouseLeftButtonUp += Instance.DragSource_PreviewMouseLeftButtonUp;
dragSource.PreviewMouseMove += Instance.DragSource_PreviewMouseMove;
dragSource.PreviewTouchDown += Instance.DragSource_PreviewTouchDown;
dragSource.PreviewTouchUp += Instance.DragSource_PreviewTouchUp;
dragSource.PreviewTouchMove += Instance.DragSource_PreviewTouchMove;
}
}
private void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!Skip(e.OriginalSource as Visual))
{
DownSetup(sender, e.OriginalSource as Visual, e);
Down(sender, e.GetPosition(selectedTarget));
}
}
private void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (!Skip(e.OriginalSource as Visual))
{
if (!adornerCaptured && dragData != null)
{
if (DragDropUIHelper.IsMovementBigEnough(initialPoint, e.GetPosition(topWindow)))
{
dragDropAdorner = (DragDropAdornerBase)GetDragDropControl(sender as DependencyObject);
dragDropAdorner.DataContext = dragData;
dragDropAdorner.Opacity = 0.8;
dragDropAdornerLayer.Visibility = Visibility.Visible;
dragDropAdornerLayer.Children.Clear();
dragDropAdornerLayer.Children.Add(dragDropAdorner);
adornerCaptured = Mouse.Capture(dragDropAdorner);
Canvas.SetLeft(dragDropAdorner, initialPoint.X - 20);
Canvas.SetTop(dragDropAdorner, initialPoint.Y - 15);
dragDropAdornerLayer.PreviewMouseMove += DragDropAdornerLayer_PreviewMouseMove;
dragDropAdornerLayer.PreviewMouseUp += DragDropAdornerLayer_PreviewMouseUp;
}
}
}
}
private void DragSource_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!Skip(e.OriginalSource as Visual))
{
Clear();
}
}
private void DragSource_PreviewTouchDown(object sender, TouchEventArgs e)
{
if (!Skip(e.OriginalSource as Visual))
{
DownSetup(sender, e.OriginalSource as Visual, e);
Down(sender, e.GetTouchPoint(selectedTarget).Position);
}
}
private void DragSource_PreviewTouchMove(object sender, TouchEventArgs e)
{
if (!Skip(e.OriginalSource as Visual))
{
if (!adornerCaptured && dragData != null)
{
if (DragDropUIHelper.IsMovementBigEnough(initialPoint, e.GetTouchPoint(topWindow).Position))
{
dragDropAdorner = (DragDropAdornerBase)GetDragDropControl(sender as DependencyObject);
dragDropAdorner.DataContext = dragData;
dragDropAdorner.Opacity = 0.7;
dragDropAdornerLayer.Visibility = Visibility.Visible;
dragDropAdornerLayer.Children.Clear();
dragDropAdornerLayer.Children.Add(dragDropAdorner);
adornerCaptured = e.TouchDevice.Capture(dragDropAdorner);
Canvas.SetLeft(dragDropAdorner, initialPoint.X - 20);
Canvas.SetTop(dragDropAdorner, initialPoint.Y - 15);
dragDropAdornerLayer.PreviewTouchMove += DragDropAdornerLayer_PreviewTouchMove;
dragDropAdornerLayer.PreviewTouchUp += DragDropAdornerLayer_PreviewTouchUp;
}
}
}
}
private void DragSource_PreviewTouchUp(object sender, TouchEventArgs e)
{
if (!Skip(e.OriginalSource as Visual))
{
Clear();
}
}
private void DownSetup(object sender, Visual visual, object e)
{
try
{
topWindow = (UserControl)DragDropUIHelper.FindAncestor(typeof(UserControl), visual);
if (e is MouseButtonEventArgs)
{
initialPoint = (e as MouseButtonEventArgs).GetPosition(topWindow);
}
else
{
initialPoint = (e as TouchEventArgs).GetTouchPoint(topWindow).Position;
}
if (topWindow != null)
{
dragDropAdornerLayer = topWindow.FindName(GetAdornerLayer(sender as DependencyObject)) as Canvas;
selectedTarget = topWindow.FindName(GetDropTarget(sender as DependencyObject)) as DataGrid;
}
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(string.Format("DownSetup Exception: {0}", exception.Message));
}
}
private void Down(object sender, Point selectedTargetPoint)
{
DataGridRow row = DragDropUIHelper.TryFindFromPoint<DataGridRow>((UIElement)sender, selectedTargetPoint);
if (row == null)
{
return;
}
selectedRow = row;
dragData = row.Item;
dragDataIndex = row.GetIndex();
}
private void DragDropAdornerLayer_PreviewMouseMove(object sender, MouseEventArgs e)
{
DragDropAdornerLayerMove(e.GetPosition(selectedTarget), e.GetPosition(topWindow));
}
private void DragDropAdornerLayer_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
DragDropAdornerLayerUp();
}
private void DragDropAdornerLayer_PreviewTouchMove(object sender, TouchEventArgs e)
{
DragDropAdornerLayerMove(e.GetTouchPoint(selectedTarget).Position, e.GetTouchPoint(topWindow).Position);
}
private void DragDropAdornerLayer_PreviewTouchUp(object sender, TouchEventArgs e)
{
DragDropAdornerLayerUp();
}
private void DragDropAdornerLayerMove(Point selectedTargetPoint, Point currentPoint)
{
DataGridRow row = DragDropUIHelper.TryFindFromPoint<DataGridRow>(selectedTarget, selectedTargetPoint);
if (row != null)
{
selectedTarget.SelectedItem = row.Item;
dropTarget = row.Item;
dropTargetIndex = row.GetIndex();
}
else
{
dropTarget = null;
}
currentPoint.X = currentPoint.X - 20;
currentPoint.Y = currentPoint.Y - 15;
delta = new Point(initialPoint.X - currentPoint.X, initialPoint.Y - currentPoint.Y);
scrollTarget = new Point(initialPoint.X - delta.X, initialPoint.Y - delta.Y);
Canvas.SetLeft(dragDropAdorner, scrollTarget.X);
Canvas.SetTop(dragDropAdorner, scrollTarget.Y);
dragDropAdorner.AdornerDropState = DropState.CannotDrop;
if (dropTarget != null)
{
dragDropAdorner.AdornerDropState = DropState.CanDrop;
}
}
private void DragDropAdornerLayerUp()
{
if (dragDropAdorner != null)
{
switch (dragDropAdorner.AdornerDropState)
{
case DropState.CanDrop:
CanDropAnimation();
break;
case DropState.CannotDrop:
CannotDropAnimation();
break;
}
}
Clear();
dragDropAdornerLayer.PreviewMouseMove -= DragDropAdornerLayer_PreviewMouseMove;
dragDropAdornerLayer.PreviewMouseUp -= DragDropAdornerLayer_PreviewMouseUp;
dragDropAdornerLayer.PreviewTouchMove -= DragDropAdornerLayer_PreviewTouchMove;
dragDropAdornerLayer.PreviewTouchUp -= DragDropAdornerLayer_PreviewTouchUp;
}
private void CanDropAnimation()
{
try
{
Storyboard dragDropAdornerStoryboard = dragDropAdorner.Resources["canDrop"] as Storyboard;
dragDropAdornerStoryboard.Completed += (s, args) =>
{
dragDropAdornerLayer.Children.Clear();
dragDropAdornerLayer.Visibility = Visibility.Collapsed;
};
dragDropAdornerStoryboard.Begin(dragDropAdorner);
if (ItemDropped == null)
{
return;
}
if (!Equals(dragData, dropTarget))
{
ItemDropped(dragDropAdorner, new DragDropEventArgs(dragData, dropTarget, dragDataIndex, dropTargetIndex));
}
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(string.Format("CanDropAnimation Exception: {0}", exception));
}
}
private void CannotDropAnimation()
{
try
{
Storyboard dragDropAdornerStoryboard = dragDropAdorner.Resources["cannotDrop"] as Storyboard;
DoubleAnimation aniX = dragDropAdornerStoryboard.Children[0] as DoubleAnimation;
DoubleAnimation aniY = dragDropAdornerStoryboard.Children[1] as DoubleAnimation;
aniX.To = delta.X;
aniY.To = delta.Y;
dragDropAdornerStoryboard.Completed += (s, args) =>
{
dragDropAdornerLayer.Children.Clear();
dragDropAdornerLayer.Visibility = Visibility.Collapsed;
};
dragDropAdornerStoryboard.Begin(dragDropAdorner);
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(string.Format("CannotDropAnimation Exception: {0}", exception));
}
}
private void Clear()
{
if (dragDropAdorner != null)
{
dragDropAdorner.ReleaseMouseCapture();
dragDropAdorner.ReleaseAllTouchCaptures();
}
dragData = null;
adornerCaptured = false;
}
private bool Skip(Visual visual)
{
if (visual is Button || visual is ComboBox || visual is Image)
{
return true;
}
else
{
return false;
}
}
}
public enum DropState
{
CanDrop = 1,
CannotDrop = 2
}
public class DragDropEventArgs : EventArgs
{
public object DragData;
public object TargetData;
public int DragDataIndex;
public int TargetDataIndex;
public DragDropEventArgs()
{
}
public DragDropEventArgs(object dragData, object targetData, int dragDataIndex, int targetDataIndex)
{
DragData = dragData;
TargetData = targetData;
DragDataIndex = dragDataIndex;
TargetDataIndex = targetDataIndex;
}
}
public class DragDropAdornerBase : UserControl
{
public DropState AdornerDropState
{
get { return (DropState)GetValue(AdornerDropStateProperty); }
set { SetValue(AdornerDropStateProperty, value); }
}
public static readonly DependencyProperty AdornerDropStateProperty = DependencyProperty.Register("AdornerDropState", typeof(DropState), typeof(DragDropAdornerBase));
}
public static class DragDropUIHelper
{
public static T TryFindParent<T>(DependencyObject child) where T : DependencyObject
{
DependencyObject parentObject = GetParentObject(child);
if (parentObject == null)
{
return null;
}
T parent = parentObject as T;
if (parent != null)
{
return parent;
}
else
{
return TryFindParent<T>(parentObject);
}
}
public static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null)
{
return null;
}
ContentElement contentElement = child as ContentElement;
if (contentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null)
{
return parent;
}
FrameworkContentElement fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
return VisualTreeHelper.GetParent(child);
}
public static void UpdateBindingSources(DependencyObject obj, params DependencyProperty[] properties)
{
foreach (DependencyProperty depProperty in properties)
{
BindingExpression be = BindingOperations.GetBindingExpression(obj, depProperty);
if (be != null)
{
be.UpdateSource();
}
}
int count = VisualTreeHelper.GetChildrenCount(obj);
for (int i = 0; i < count; i++)
{
DependencyObject childObject = VisualTreeHelper.GetChild(obj, i);
UpdateBindingSources(childObject, properties);
}
}
public static T TryFindFromPoint<T>(UIElement reference, Point point) where T : DependencyObject
{
DependencyObject element = reference.InputHitTest(point) as DependencyObject;
if (element == null)
{
return null;
}
else if (element is T)
{
return (T)element;
}
else
{
return TryFindParent<T>(element);
}
}
public static FrameworkElement FindAncestor(Type ancestorType, Visual visual)
{
while (visual != null && !ancestorType.IsInstanceOfType(visual))
{
visual = (Visual)VisualTreeHelper.GetParent(visual);
}
return visual as FrameworkElement;
}
public static bool IsMovementBigEnough(Point initialMousePosition, Point currentPosition)
{
return (Math.Abs(currentPosition.X - initialMousePosition.X) >= SystemParameters.MinimumHorizontalDragDistance || Math.Abs(currentPosition.Y - initialMousePosition.Y) >= SystemParameters.MinimumVerticalDragDistance);
}
}
}