Can't get simple WPF drag and drop to work

10,991

Solution 1

This might be some strange case, but to fix it, I needed to handle or dragging events, including the Preview versions.

Here's how to make it work.

Xaml:

<Window x:Class="DayPlanner.View.DnDTestBasic"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DnDTestBasic" Height="200" Width="200">
    <StackPanel>
        <Button Name="button" 
                Content="OK" 
                PreviewMouseLeftButtonDown="button_PreviewMouseLeftButtonDown" 
                PreviewMouseMove="button_PreviewMouseMove"/>
        <TextBox Name="textBox"
                 AllowDrop="True"
                 PreviewDragEnter="textBox_Dragging"
                 DragEnter="textBox_Dragging"
                 PreviewDragOver="textBox_Dragging"
                 DragOver="textBox_Dragging"
                 Drop="textBox_Drop"/>
        <TextBlock Name="status"
                   Text="No dragging"/>
    </StackPanel>
</Window>

Code:

public partial class DnDTestBasic : Window
{
    public DnDTestBasic()
    {
        InitializeComponent();
    }

    private Point dragStartPoint;

    private void button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        dragStartPoint = e.GetPosition(null);
        status.Text = "New drag start position";
    }

    private static bool IsDragging(Point dragStartPoint, MouseEventArgs e)
    {
        var diff = e.GetPosition(null) - dragStartPoint;
        return
            e.LeftButton == MouseButtonState.Pressed &&
            (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
             Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance);
    }

    private void button_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (IsDragging(dragStartPoint, e))
        {
            status.Text = "Starting drag...";
            DragDrop.DoDragDrop(button, new DataObject("Button", button), DragDropEffects.Copy);
            status.Text = "Dragging done.";
            e.Handled = true;
        }
    }

    private void textBox_Dragging(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("Button"))
            e.Effects = DragDropEffects.Copy;
        else
            e.Effects = DragDropEffects.None;
        e.Handled = true;
    }

    private void textBox_Drop(object sender, DragEventArgs e)
    {
        var button = (Button)e.Data.GetData("Button");
        textBox.Text = string.Format("[{0}]", button.Content.ToString());
        e.Handled = true;
    }
}

Solution 2

I believe it has to do with the fact that when you start the drag event, the button control is capturing mouse input. Any mouse movements you do after that are registered to the button instead of to the application

I actually had a similar problem and ended up using MouseEnter/Leave events instead of the built in WPF drag/drop framework.

Share:
10,991
Stefan
Author by

Stefan

Updated on June 04, 2022

Comments

  • Stefan
    Stefan almost 2 years

    For a simple test I want to drag a Button to a TextBox. I can start dragging the Button, but the Drop event is not raised. What am I missing?

    Xaml:

    <Window x:Class="DayPlanner.View.DnDTest"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="DnDTest" Height="200" Width="200">
        <StackPanel>
            <Button Name="button" 
                    Content="OK" 
                    PreviewMouseLeftButtonDown="button_PreviewMouseLeftButtonDown" 
                    PreviewMouseMove="button_PreviewMouseMove"/>
            <TextBox Name="textBox"
                     AllowDrop="True"
                     DragEnter="textBox_DragEnter"
                     Drop="textBox_Drop"/>
        </StackPanel>
    </Window>
    

    Code:

    public partial class DnDTest : Window
    {
        public DnDTest()
        {
            InitializeComponent();
        }
    
        private Point dragStartPoint;
    
        private void button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            dragStartPoint = e.GetPosition(null);
        }
    
        private static bool IsDragging(Point dragStartPoint, MouseEventArgs e)
        {
            var diff = e.GetPosition(null) - dragStartPoint;
            return
                e.LeftButton == MouseButtonState.Pressed &&
                (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
                    Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance);
        }
    
        private void button_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (IsDragging(dragStartPoint, e))
            {
                DragDrop.DoDragDrop(button, new DataObject("Button", button), DragDropEffects.Move);
                e.Handled = true;
            }
        }
    
        private void textBox_DragEnter(object sender, DragEventArgs e)
        {
            e.Handled = true;
        }
    
        private void textBox_Drop(object sender, DragEventArgs e)
        {
            var button = (Button)e.Data.GetData("Button");
            textBox.Text = string.Format("[0]", button.Content.ToString());
            e.Handled = true;
        }
    }