{"id":48573,"date":"2021-03-04T10:28:44","date_gmt":"2021-03-04T18:28:44","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/xamarin\/?p=48573"},"modified":"2021-03-03T14:29:50","modified_gmt":"2021-03-03T22:29:50","slug":"collectionview-drag-and-drop","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/collectionview-drag-and-drop\/","title":{"rendered":"CollectionView Drag &#038; Drop Item Reordering with Gesture Recognizers"},"content":{"rendered":"<p>Items reordering in a list-based control is a handy feature and it is used in various use cases. From simple scenarios like configuring settings, defining tabs order to complex scenarios like managing user content, and reordering images or email. With the recent <a href=\"https:\/\/devblogs.microsoft.com\/xamarin\/xamarin-forms-5-0-is-here\/\">Xamarin.Forms 5.0<\/a> release, <a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/xamarin-forms\/app-fundamentals\/gestures\/drag-and-drop\">Drag and Drop gesture recognizers<\/a> were introduced and enable you to unlock these scenarios in your app. In this post I will guide you through everything you need to add drag &amp; drop to your CollectionView.<\/p>\n<h2>Drag &amp; Drop Gesture Recognizers<\/h2>\n<p>In previous posts you may have seen how drag and drop can be used with any control with the new gesture recognizers in Xamarin.Forms. However, views inside <code>CollectionView<\/code> organized by the control itself, are special and include caching and virtualization. These optimizations can break if you start moving views around. Don&#8217;t worry those as gesture recognizers can still be used to work with the views indirectly. The recognizers have useful properties to bind them to commands with parameters:<\/p>\n<pre><code class=\"xml\">    &lt;DragGestureRecognizer\n        ...\n        DragStartingCommand=\"{Binding ...}\"\n        DragStartingCommandParameter=\"{Binding ...}\" \/&gt;\n\n    &lt;DropGestureRecognizer\n        ...\n        DragOverCommand=\"{Binding ...}\"\n        DragOverCommandParameter=\"{Binding ...}\"\n        DragLeaveCommand=\"{Binding ...}\"\n        DragLeaveCommandParameter=\"{Binding ...}\"\n        DropCommand=\"{Binding ...}\"\n        DropCommandParameter=\"{Binding ...}\" \/&gt;\n<\/code><\/pre>\n<p>This is enough to track user requests to move one item to some other location. The <code>item<\/code> here is an element of a collection, bound to the <code>CollectionView<\/code> control. And if you can change the order of the items in the underlying collection, you can do the same with the new gesture recognizers.<\/p>\n<h2>Reorder Items<\/h2>\n<p>First, you need a view model with a collection, where you want to reorder items. The items reordering logic is defined in C# with no UI-dependent code. A basic algorithm that takes one item of a collection and moves it in front of another item of the same collection. You need a few properties in the view model and the core reordering logic:<\/p>\n<pre><code class=\"csharp\">    public ICommand ItemDragged { get; }\n    public ICommand ItemDraggedOver { get; }\n    public ICommand ItemDragLeave { get; }\n    public ICommand ItemDropped { get; }\n\n\n    private async Task OnItemDropped(ItemViewModel item)\n    {\n        var itemToMove = items.First(i =&gt; i.IsBeingDragged);\n        var itemToInsertBefore = item;\n        if (itemToMove == null || itemToInsertBefore == null || itemToMove == itemToInsertBefore)\n            return;\n\n        var categoryToMoveFrom = GroupedItems.First(g =&gt; g.Contains(itemToMove));\n        categoryToMoveFrom.Remove(itemToMove);\n\n        var categoryToMoveTo = GroupedItems.First(g =&gt; g.Contains(itemToInsertBefore));\n        var insertAtIndex = categoryToMoveTo.IndexOf(itemToInsertBefore);\n        itemToMove.Category = categoryToMoveFrom.Name;\n        categoryToMoveTo.Insert(insertAtIndex, itemToMove);\n        itemToMove.IsBeingDragged = false;\n        itemToInsertBefore.IsBeingDraggedOver = false;\n    }\n<\/code><\/pre>\n<p>Next, to make it closer to a real-world example, the items in the <code>CollectionView<\/code> are grouped by category. And the algorithm above can drag items between categories:<\/p>\n<pre><code class=\"csharp\">    public class ItemViewModel : ObservableObject\n    {\n        public string Category { get; set; }\n        public string Title { get; set; }\n\n        private bool isBeingDragged;\n        public bool IsBeingDragged\n        {\n            get { return isBeingDragged; }\n            set { SetProperty(ref isBeingDragged, value); }\n        }\n\n        private bool isBeingDraggedOver;\n        public bool IsBeingDraggedOver\n        {\n            get { return isBeingDraggedOver; }\n            set { SetProperty(ref isBeingDraggedOver, value); }\n        }\n    }\n<\/code><\/pre>\n<p>Finally, you need to disable any Drag and Drop logic defined by the gestures using the <code>Drop<\/code> event. This ensures that only the logic defined by the view model is used to reorder items:<\/p>\n<pre><code class=\"csharp\">    private void DropGestureRecognizer_Drop_Collection(System.Object sender, Xamarin.Forms.DropEventArgs e)\n    {\n        e.Handled = true;\n    }\n<\/code><\/pre>\n<p><figure id=\"attachment_48574\" aria-labelledby=\"figcaption_attachment_48574\" class=\"wp-caption aligncenter\" ><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2021\/02\/xamarinforms-collectionview-groupeditems-reordering.gif\" alt=\"xamarinforms-collectionview-groupeditems-reordering.gif\" width=\"600\" height=\"569\" class=\"size-full wp-image-48574\" \/><figcaption id=\"figcaption_attachment_48574\" class=\"wp-caption-text\">]<a href=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2021\/02\/xamarinforms-collectionview-groupeditems-reordering.gif\">5<\/a> xamarinforms collectionview grouped items reordering<\/figcaption><\/figure><\/p>\n<h2>Summary<\/h2>\n<p>You can reorder items in a <code>CollectionView<\/code> by reordering items in the underlying collection bound to the <code>CollectionView<\/code>. The Drag and Drop gesture recognizers can help you to trigger the reordering logic, defined by a view model, that holds the collection. This solution doesn\u2019t use any native code, the items reordering logic is defined in a view model while the gesture recognizers take advantage of the MVVM to communicate with that logic. You can also customize the look and feel for an item being dragged and a targeted area, everything in XAML with HotReload enabled. You can use this solution today with any collection-based control, taking <a href=\"https:\/\/github.com\/xamcat\/grouped-list-reorder\">this sample repo<\/a> as a starting point.<\/p>\n<h2>Useful links<\/h2>\n<ol>\n<li><a href=\"https:\/\/github.com\/xamcat\/grouped-list-reorder\">Collection View items reordering sample<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/xamarin\/Xamarin.Forms\/issues\/4676\">Enhancement Support drag-and-drop reordering in CollectionView<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/xamarin-forms\/app-fundamentals\/gestures\/drag-and-drop\">Drag and Drop gesture recognizers docs<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/samples\/xamarin\/xamarin-forms-samples\/workingwithgestures-draganddropgesture\/\">Drag and Drop gesture recognizers sample<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/xamarin-forms\/user-interface\/collectionview\/introduction\">CollectionView control<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/xamarin\/xamarin-forms\/user-interface\/collectionview\/grouping\">CollectionView grouping<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Items reordering in a list-based control is a handy feature and it is used in various use cases. From simple scenarios like configuring settings, defining tabs order to complex scenarios like managing user content, and reordering images or email. With the recent Xamarin.Forms 5.0 release, Drag and Drop gesture recognizers were introduced and enable you [&hellip;]<\/p>\n","protected":false},"author":18565,"featured_media":48574,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2,556,367,7745],"tags":[751,9198,9197,9168],"class_list":["post-48573","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","category-integrations","category-xamarin-forms","category-xaml","tag-collectionview","tag-drag-and-drop","tag-gesture-recognizers","tag-xamarin-forms-5"],"acf":[],"blog_post_summary":"<p>Items reordering in a list-based control is a handy feature and it is used in various use cases. From simple scenarios like configuring settings, defining tabs order to complex scenarios like managing user content, and reordering images or email. With the recent Xamarin.Forms 5.0 release, Drag and Drop gesture recognizers were introduced and enable you [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/48573","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/18565"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=48573"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/48573\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/48574"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=48573"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=48573"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=48573"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}