I am displaying my collectionview in the below format:
0 Item 1 Item
2 Item1 3 Item
4 Item2 5 Item
The Numbers are the Index..Now after a drag and drop in the my CollectionView after dragging 2 before 5 i am seeing this:
0 Item 1 Item
3 Item1 4 Item
5 Item2 5 Item
Using the below code to display the indexes on initial load
public class IndexValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter is Binding binding &&
value is ModelData score &&
binding.Source is CollectionView collectionView &&
collectionView.BindingContext is NewLocationListViewModel viewModel)
{
return viewModel.SortingList.IndexOf(score);
}
return -1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
How to get the indexes to correct themselves after the drag and drop ?
Using a CollectionView in Xamarin Forms
<controls:CollectionViewWithDragAndDrop Margin="0,50,0,0"
ItemsSource="{Binding SortingStorageList}" ItemsUpdatingScrollMode="KeepLastItemInView" PropertyChanged="CollectionViewWithDragAndDrop_PropertyChanged">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Spacing="0" Padding="5" Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Grid ColumnSpacing="10" ColumnDefinitions="20*,Auto" HorizontalOptions="CenterAndExpand">
<Label Grid.Column="0"
FontSize="Large" FontAttributes="Bold"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Text="{Binding ., Converter={StaticResource IndexConverter}, ConverterParameter={Binding Source={x:Reference storageLocationsCollectionView}, Path=BindingContext}}"
TextColor="{StaticResource TextBlackColor}"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center" />
<Frame Grid.Column="1"
Padding="5"
BorderColor="{StaticResource TextBlackColor}"
CornerRadius="8"
HasShadow="True" HeightRequest="40"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
WidthRequest="300">
<Label
FontSize="Large"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="Center"
Text="{Binding StorageLocation}"
TextColor="{StaticResource TextBlackColor}"
VerticalOptions="CenterAndExpand"
VerticalTextAlignment="Center" />
</Frame>
</Grid>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</controls:CollectionViewWithDragAndDrop>
Renderer:
public class CollectionViewWithDragAndDropRenderer : CollectionViewRenderer,IUICollectionViewDragDelegate, IUICollectionViewDropDelegate
{
//to find the starting index of the drag position
int indexsource = 0;
/// <summary>
/// To set the Native control properties here
/// </summary>
/// <param name="e"></param>
protected override void OnElementChanged(ElementChangedEventArgs<GroupableItemsView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
try
{
//load the collection view from the view contoller
if (Control.PreferredFocusEnvironments[0] is UICollectionView collection)
{
var longPressGesture = new UILongPressGestureRecognizer(
gesture =>
{
switch (gesture.State)
{
case UIGestureRecognizerState.Began:
break;
case UIGestureRecognizerState.Changed:
break;
case UIGestureRecognizerState.Ended:
break;
default:
collection.CancelInteractiveMovement();
break;
}
});
// Add the custom recognizer to the collection view
if (collection != null)
{
collection?.AddGestureRecognizer(longPressGesture);
collection.DragInteractionEnabled = true;
collection.DragDelegate = this;
collection.DropDelegate = this;
}
}
}
catch (Exception ex)
{
LazyServiceFromIOC<IAnalytics>.Instance.RequestedService?.LogException(nameof(CollectionViewWithDragAndDropRenderer), ex);
}
}
}
/// <summary>
/// draw the drag view over the collection while dragging
/// </summary>
/// <param name="collectionView"></param>
/// <param name="session"></param>
/// <param name="indexPath"></param>
/// <returns></returns>
public UIDragItem[] GetItemsForBeginningDragSession(UICollectionView collectionView, IUIDragSession session, NSIndexPath indexPath)
{
if (indexPath != null)
indexsource = indexPath.Row;
return new UIDragItem[] { new UIDragItem(new NSItemProvider()) };
}
/// <summary>
/// return ture to set that cell can handle the drag
/// </summary>
/// <param name="collectionView"></param>
/// <param name="session"></param>
/// <returns></returns>
[Export("collectionView:canHandleDropSession:")]
public bool CanHandleDropSession(UICollectionView collectionView, IUIDropSession session)
{
return true;
}
/// <summary>
/// Check whether drag is outside the app or inside the app adn perform action based on that
/// </summary>
/// <param name="collectionView"></param>
/// <param name="session"></param>
/// <param name="destinationIndexPath"></param>
/// <returns></returns>
[Export("collectionView:dropSessionDidUpdate:withDestinationIndexPath:")]
public UICollectionViewDropProposal DropSessionDidUpdate(UICollectionView collectionView, IUIDropSession session, NSIndexPath destinationIndexPath)
{
if (session!=null && session.LocalDragSession != null)
{
return new UICollectionViewDropProposal(UIDropOperation.Move, UICollectionViewDropIntent.InsertAtDestinationIndexPath);
}
else
{
return new UICollectionViewDropProposal(UIDropOperation.Copy, UICollectionViewDropIntent.InsertAtDestinationIndexPath);
}
}
/// <summary>
/// Drop the dragged item and perfrom the sort logic which updates the forms Element Item source
/// </summary>
/// <param name="collectionView"></param>
/// <param name="coordinator"></param>
public void PerformDrop(UICollectionView collectionView, IUICollectionViewDropCoordinator coordinator)
{
var destinationIndexPath = coordinator?.DestinationIndexPath ?? NSIndexPath.FromRowSection(0, 0);
switch (coordinator?.Proposal?.Operation)
{
case UIDropOperation.Move:
var items = coordinator?.Items;
var hasSourceIndex = items?.FirstOrDefault(i => i.SourceIndexPath != null);
var containsSourceIndex = items?.ToList().Contains(hasSourceIndex);
if (hasSourceIndex != null)
{
var itemsSourceList = Element?.ItemsSource as IList;
var itemtomove = itemsSourceList[indexsource];
itemsSourceList?.RemoveAt(indexsource);
itemsSourceList?.Insert(destinationIndexPath.Row, itemtomove);
var res = Element as CollectionViewWithDragAndDrop;
res?.InvokeDropCommand();
}
break;
default:
return;
}
}
}
SortingStorgeList:
SortingStorageList = new ObservableCollection<ModelData>(storageLocations);