WinUI3 Getting the index where the item was moved in a ListView

Cosmin Mihai 35 Reputation points
2023-10-25T11:45:42.5+00:00

Having ListView, how can I get the index in the list where the item from the same list was dropped?(Reordering) I tried using the following callbacks, but neither DragItemsCompletedEventArgs or OnDropIntoStagedPhotos seem to have an appropriate method.

void TableContentPage::OnStagedDragItemsCompleted(
    [[maybe_unused]] ::winrt::Windows::Foundation::IInspectable const &,
    [[maybe_unused]] ::winrt::Microsoft::UI::Xaml::Controls::
        DragItemsCompletedEventArgs const &args)
{

}

void TableContentPage::OnDropIntoStagedPhotos(
    [[maybe_unused]] Windows::Foundation::IInspectable const  &sender,
    [[maybe_unused]] Microsoft::UI::Xaml::DragEventArgs const &args)
{
}

I'm using the following ListView attributes:

<ListView x:Name="ListViewName"
          Grid.Row="0"
          Grid.Column="0"
          ScrollViewer.HorizontalScrollMode="Enabled"
          ScrollViewer.HorizontalScrollBarVisibility="Visible"
          ScrollViewer.IsHorizontalRailEnabled="True"
          CanDragItems="True"
          CanReorderItems="True"
          IsSwipeEnabled="True"
          HorizontalAlignment="Stretch"
          AllowDrop="True"
          Background="{StaticResource PrimaryColor}"
          Drop="OnDropIntoStagedPhotos"
          DragOver="OnDragOverStagedPhotos"
          DragItemsCompleted="OnStagedDragItemsCompleted"
          DragItemsStarting="OnStagedDragItemsStarting"
          SelectionMode="Extended"
          SelectionChanged="OnStagedPhotosSelectionChanged">
Windows development | Windows App SDK
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. Cosmin Mihai 35 Reputation points
    2023-10-27T13:43:14.1666667+00:00

    I came to the conclusion that the structure underlying the UI should be used for this purpose.

    For example IObservableVector VectorChanged can contain a callback where the changed indexes are provided.

    imageCollection is of type IObservableVector

    
      imageCollection.VectorChanged(
          [](IObservableVector<IInspectable> const &sender,
             IVectorChangedEventArgs const         &args) {
            // Changed index
            args.Index();
            // The type of change
            args.CollectionChange();
          });
    
    1 person found this answer helpful.

  2. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2023-10-26T02:34:17.1233333+00:00

    ListViewBase.DragItemsCompleted gives the dragged items and with IVector<T>.IndexOf, you can retrieve the index. So, we only need to distinguish between reorder and move. It's necessary for the destination to give the difference.

    There is a UWP XamlDragAndDrop sample you can refer to.GIF 10-26-2023 10-33-06 AM


  3. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2023-11-02T05:17:43.2366667+00:00

    Hello @Cosmin Mihai,

    As far as two ListView controls are concerned, you can refer to the WinUI-Gallery sample which finds the index based on the calculation of the coordinate of the dragged item and item height.

                        // Find the insertion index:
                        Windows.Foundation.Point pos = e.GetPosition(target.ItemsPanelRoot);
    
                        // If the target ListView has items in it, use the height of the first item
                        //      to find the insertion index.
                        int index = 0;
                        if (target.Items.Count != 0)
                        {
                            // Get a reference to the first item in the ListView
                            ListViewItem sampleItem = (ListViewItem)target.ContainerFromIndex(0);
    
                            // Adjust itemHeight for margins
                            double itemHeight = sampleItem.ActualHeight + sampleItem.Margin.Top + sampleItem.Margin.Bottom;
    
                            // Find index based on dividing number of items by height of each item
                            index = Math.Min(target.Items.Count - 1, (int)(pos.Y / itemHeight));
    
                            // Find the item being dropped on top of.
                            ListViewItem targetItem = (ListViewItem)target.ContainerFromIndex(index);
    
                            // If the drop position is more than half-way down the item being dropped on
                            //      top of, increment the insertion index so the dropped item is inserted
                            //      below instead of above the item being dropped on top of.
                            Windows.Foundation.Point positionInItem = e.GetPosition(targetItem);
                            if (positionInItem.Y > itemHeight / 2)
                            {
                                index++;
                            }
    
                            // Don't go out of bounds
                            index = Math.Min(target.Items.Count, index);
                        }
                        // Only other case is if the target ListView has no items (the dropped item will be
                        //      the first). In that case, the insertion index will remain zero.
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.