microsoft-ui-xaml icon indicating copy to clipboard operation
microsoft-ui-xaml copied to clipboard

TreeView Drop Event not triggering for its children TreeView items drag and drop.

Open mattcode1521 opened this issue 7 months ago • 1 comments

Describe the bug

When using the TreeView object, the Drop event is not triggered correctly. It only works when hovering another TreeView item and putting back the dragged item at its original place.

When dropping an item on another item, or dragging an item and dropping it to a new location, the drop event is never triggered.

Steps to reproduce the bug

Scenario 1 (triggers the dropped event) :

  1. Pick a treeview item to be dragged
  2. Drag it slightly over another treeview item
  3. Put it back at it's original place.

Scenario 2 (not triggering the drop event) :

  1. Pick an item to be dragged
  2. drag it directly on another treeview item
  3. drop it

Scenario 3 (not triggering the drop event):

  1. Pick a treeview item to be dragged
  2. drag it to a new location in the treeview (not on another item)
  3. drop it

Expected behavior

All of these scenarios should trigger the Drop event as all the targets location are valid, but they aren't. In my code, only the children treeview item are bound to the TreeViewItem_Drop method. So only those are expected to call the method (those in the FileTemplate datatemplate).

Screenshots

Image

NuGet package version

WindowsAppSDK 1.7.250513003

Windows version

Windows 11

Additional context

*MainWindow.Xaml

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="TreeView_Drop.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TreeView_Drop"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="TreeView-Drop">

    <Grid Name="MainGrid">
        <Grid.Resources>
            <!-- DataTemplate for folders -->
            <DataTemplate x:Key="FolderTemplate" x:DataType="local:ExplorerItem">
                <TreeViewItem AutomationProperties.Name="{x:Bind Name}"
         ItemsSource="{x:Bind Children}" IsExpanded="True">
                    <StackPanel Orientation="Horizontal">
                        <Image Width="20" Source="../Assets/SampleMedia/folder.png"/>
                        <TextBlock Margin="0,0,10,0"/>
                        <TextBlock Text="{x:Bind Name}" />
                    </StackPanel>
                </TreeViewItem>
            </DataTemplate>

            <!-- DataTemplate for files -->
            <DataTemplate x:Key="FileTemplate" x:DataType="local:ExplorerItem">
                <TreeViewItem AutomationProperties.Name="{x:Bind Name}" Drop="TreeViewItem_Drop">
                    <StackPanel Orientation="Horizontal">
                        <FontIcon Glyph="&#xE8A5;" />
                        <TextBlock Margin="0,0,10,0"/>
                        <TextBlock Text="{x:Bind Name}"/>
                    </StackPanel>
                </TreeViewItem>
            </DataTemplate>

            <!-- Template selector for ExplorerItem types -->
            <local:ExplorerItemTemplateSelector x:Key="ExplorerItemTemplateSelector"
     FolderTemplate="{StaticResource FolderTemplate}"
     FileTemplate="{StaticResource FileTemplate}" />
        </Grid.Resources>

        <!-- TreeView bound to DataSource, using the ItemTemplateSelector -->
        <TreeView ItemsSource="{x:Bind DataSource}"
              ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}" 
                  CanDragItems="True"
                  AllowDrop="True"/>
    </Grid>

</Window>

MainWindow.Xaml.cs

using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace TreeView_Drop
{
    public sealed partial class MainWindow : Window
    {
        public ObservableCollection<ExplorerItem> DataSource { get; set; }

        public MainWindow()
        {
            this.InitializeComponent();
            DataSource = GetData();
            MainGrid.DataContext = this;
        }

        private ObservableCollection<ExplorerItem> GetData()
        {
            return new ObservableCollection<ExplorerItem>
            {
                new ExplorerItem
                {
                    Name = "Documents",
                    Type = ExplorerItem.ExplorerItemType.Folder,
                    Children =
                    {
                        new ExplorerItem
                        {
                            Name = "ProjectProposal",
                            Type = ExplorerItem.ExplorerItemType.File,
                        },
                        new ExplorerItem
                        {
                            Name = "BudgetReport",
                            Type = ExplorerItem.ExplorerItemType.File,
                        },
                    },
                },
                new ExplorerItem
                {
                    Name = "Projects",
                    Type = ExplorerItem.ExplorerItemType.Folder,
                    Children =
                    {
                        new ExplorerItem
                        {
                            Name = "Project Plan",
                            Type = ExplorerItem.ExplorerItemType.File,
                        },
                    },
                },
            };
        }

        private void TreeViewItem_Drop(object sender, DragEventArgs e)
        {
            Debug.WriteLine("Dropped");
        }
    }
    public class ExplorerItem
    {
        public enum ExplorerItemType
        {
            Folder,
            File,
        }

        public string Name { get; set; }
        public ExplorerItemType Type { get; set; }
        public ObservableCollection<ExplorerItem> Children { get; set; } = new ObservableCollection<ExplorerItem>();
    }

    class ExplorerItemTemplateSelector : DataTemplateSelector
    {
        // Template to use for folder items in the TreeView.
        public DataTemplate FolderTemplate { get; set; }

        // Template to use for file items in the TreeView.
        public DataTemplate FileTemplate { get; set; }

        // Determines which template to use for each item in the TreeView based on its type.
        protected override DataTemplate SelectTemplateCore(object item)
        {
            // Cast the item to the ExplorerItem type.
            var explorerItem = (ExplorerItem)item;

            // Return the appropriate template: FolderTemplate for folders, FileTemplate for files.
            return explorerItem.Type == ExplorerItem.ExplorerItemType.Folder
                ? FolderTemplate
                : FileTemplate;
        }
    }
}

mattcode1521 avatar May 26 '25 01:05 mattcode1521

I was able to repro it in my local. The drag and drop at the same location are triggering the dropped event, moving to other location isn't. This seems like by design, but requires some investigation to confirm.

hiteshkrmsft avatar Jun 04 '25 05:06 hiteshkrmsft