CollectionView Re-rodering Indexes after Drag and Drop in Xamarin Forms

52 Views Asked by At

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);
0

There are 0 best solutions below