Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF drag and drop files onto TreeView from windows explorer

I am trying to make an extremely simple, or so I thought, program to drag and drop a file from the desktop/explorer onto a wpf treeview.

The treeview in this example is simple so that I could isolate the drag and drop problem I am having. I have set AllowDrop equals True all over the place, I still can't get the Drop or DragOver events to fire. I am focused on a treeview control because I want to be able to drag files into different nodes with a hierarchical structure. Right now I would settle for just being able to get the DragOver or Drop events to fire when I drag a file onto the treeview.

I have gotten started by looking at examples such as this: Drag & Drop in Treeview

My question is similiar to this one: Drag drop files from explorer onto Telerik WPF treeview. However I am using the wpf treeview, not the telerik one.

Here is the code I have so far

XAML:

   <Window x:Class="WpfDragAndDropTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfDragAndDropTest"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TreeView Name="TreeView1">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}" >
                    <Setter Property="TreeViewItem.AllowDrop" Value="True"/>
                    <EventSetter Event="TreeViewItem.DragOver" Handler="TreeView1_DragOver" />
                    <EventSetter Event="TreeViewItem.Drop" Handler="TreeView1_Drop" />
                    <EventSetter Event="TreeViewItem.MouseMove" Handler="TreeView1_MouseMove" />
                </Style>
            </TreeView.ItemContainerStyle>

            <TreeView.Resources>
                <DataTemplate DataType="{x:Type local:TestClass}">
                    <StackPanel Orientation="Vertical"  >
                        <TextBlock Text="{Binding Path=Title}" />
                        <TextBlock Text="{Binding Path=Url}" />
                    </StackPanel>
                </DataTemplate>
            </TreeView.Resources>

        </TreeView>
    </Grid>
    </Window>

Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfDragAndDropTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        TreeView1.ItemsSource = new[] 
        { 
            new TestClass { Title = "Google", Url = "http://www.google.com" }, 
            new TestClass { Title = "Microsoft", Url = "http://www.microsoft.com" },
            new TestClass{ Title="Netflix", Url="http://www.netflix.com" }
        };
    }

    private void TreeView1_Drop(object sender, DragEventArgs e)
    {

    }

    private void TreeView1_DragOver(object sender, DragEventArgs e)
    {

    }

    private void TreeView1_MouseMove(object sender, MouseEventArgs e)
    {

    }
}


public class TestClass
{
    public string Title { get; set; }
    public string Url { get; set; }
}
}

Edit I bolded the text that spells out my problem as the events not firing.

I switched my xaml to this and I still get a black circle with a line through it when dragging a file over the treeview and the only event that fires is the MouseMove. The Drag and Drop do not fire if I use the mouse to perform those actions.

    <TreeView Name="TreeView1" AllowDrop="True" DragOver="TreeView1_DragOver" Drop="TreeView1_Drop" MouseMove="TreeView1_MouseMove">


        <TreeView.Resources>
            <DataTemplate DataType="{x:Type local:TestClass}">
                <StackPanel Orientation="Vertical"  >
                    <TextBlock Text="{Binding Path=Title}" />
                    <TextBlock Text="{Binding Path=Url}" />
                </StackPanel>
            </DataTemplate>
        </TreeView.Resources>

    </TreeView>

Edit I tried a blank treeview and was able to drag a file over it, and the cursor was not the black circle with the line through it.

<TreeView Height="312" Background="#FFCFDBF9" AllowDrop="True"/>

However when that DataTemplate is added to it, that's when the black circle starts showing up. This must be some kind of databinding issue?

Edit I'm starting to get somewhere now.

I changed my xaml to this and the events start firing:

<TreeView Name="TreeView1" Background="#FFC9D7FF">


    <TreeView.Resources>
        <DataTemplate DataType="{x:Type local:TestClass}">
            <StackPanel Orientation="Vertical"  AllowDrop="True" DragOver="TreeView1_DragOver" Drop="TreeView1_Drop" MouseMove="TreeView1_MouseMove" >
                <TextBlock Text="{Binding Path=Title}" />
                <TextBlock Text="{Binding Path=Url}" />
            </StackPanel>
        </DataTemplate>
    </TreeView.Resources>

</TreeView>

edit I have discovered that I can only drag and drop to the stackpanel if I run the project from expression blend. If I run it from visual studio it shows the black circle with a line through it. That doesn't make any sense at all. For this seperate problem I have started another question here: Visual Studio 2010 WPF Project ran in debug or relase will not allow drag and drop to any control

This is all due to running visual studio as administrator. Apparently the same is true for notepad.exe, if you run something as administrator you can't drag and drop. So now for IIS debugging I have to run as administrator and for dragging and dropping I need to figure out how to run in normal mode...

like image 691
249076 Avatar asked Sep 19 '11 19:09

249076


1 Answers

I think the issue is you are not dragging the item over the TreeViewItems themselves. This is necessary because your events are registered for the TreeViewItems only. If you want to drag and drop into a parent level of you tree, you will need to add the corresponding events to your tree.

The issue you will have with this solution is the TreeView events will fire first. So now you're going to have to know which node you're over to add it properly. There are solutions to figure out which node you are over. However, I would suggest adding a top level element to your tree that is always there. Then wire up the events to the TreeViewItems like you are. That way, you can add at a top level without having to handle the TreeView events because you can drag to that top level item.

Below is what I used to test it out and I'm seeing the breakpoints if I drag directly over the TreeViewItems. You may not recognize some namespaces but that's because it's referencing my project.

XAML:

  <TreeView x:Name="treeView">
     <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}" >
           <Setter Property="TreeViewItem.AllowDrop" Value="True"/>
           <EventSetter Event="TreeViewItem.DragOver" Handler="treeView_DragOver" />
           <EventSetter Event="TreeViewItem.Drop" Handler="treeView_Drop" />
           <EventSetter Event="TreeViewItem.MouseMove" Handler="treeView_MouseMove" />
        </Style>
     </TreeView.ItemContainerStyle>

     <TreeView.Resources>
        <DataTemplate DataType="{x:Type FileExplorerDragDrop:TestClass}">
           <StackPanel Orientation="Vertical"  >
              <TextBlock Text="{Binding Path=Title}" />
              <TextBlock Text="{Binding Path=Url}" />
           </StackPanel>
        </DataTemplate>
     </TreeView.Resources>
  </TreeView>  

Code behind:

  public MainWindow()
  {
     InitializeComponent();

     treeView.ItemsSource = new[] 
     { 
        new TestClass { Title = "Google", Url = "http://www.google.com" }, 
        new TestClass { Title = "Microsoft", Url = "http://www.microsoft.com" },
        new TestClass{ Title="Netflix", Url="http://www.netflix.com" }
     };
  }

  private void treeViewItem_DragOver(object sender, DragEventArgs e)
  {

  }

  private void treeViewItem_Drop(object sender, DragEventArgs e)
  {

  }

  private void treeViewItem_MouseMove(object sender, MouseEventArgs e)
  {

  }
like image 195
Josh Avatar answered Nov 15 '22 06:11

Josh