Search code examples
wpfcanvasdrag-and-dropdragenter

WPF DragEnter between two Canvas not firing


I am trying to drag an item from one Canvas to another. I want an event to fire when the object enters the other Canvas. None of the Drag events seem to fire. I have tried following the solution for this question, but it does not work for me: Drag and Drop not responding as expected

My canvas is this:

<Window x:Class="DragEnterTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="DragEnterMainWindow" Height="460" Width="1000">
<Grid>
    <Canvas Name="Toolbox" Background="Beige" Height="400" Width="200" Margin="12,12,800,35">
        <Rectangle Name="dragRectangle" Canvas.Left="0" Canvas.Right="0" Width="50" Height="50" Fill="Red"
                   MouseLeftButtonDown="dragRectangle_MouseLeftButtonDown"
                   MouseLeftButtonUp="dragRectangle_MouseLeftButtonUp"
                   MouseMove="dragRectangle_MouseMove"
                   />
    </Canvas>
    <Canvas Background="Azure" Height="400" Margin="218,12,0,35" Name="mainCanvas" Panel.ZIndex="-1"
            DragEnter="mainCanvas_DragEnter"
            DragLeave="mainCanvas_DragLeave"
            PreviewDragEnter="mainCanvas_PreviewDragEnter"
            PreviewDragLeave="mainCanvas_PreviewDragLeave"
            AllowDrop="True"
            DragDrop.Drop="mainCanvas_Drop"
            />
</Grid>
</Window>

If I do not have the Panel.ZIndex="-1" then the rectangle is dragged underneath the mainCanvas. This is true even if I set the ZIndex for the rectangle to some positive value.

My code is the following, modified by examples I have found:

namespace DragEnterTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    private bool _isRectDragInProg;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void dragRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isRectDragInProg = true;
        dragRectangle.CaptureMouse();
    }

    private void dragRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _isRectDragInProg = false;
        dragRectangle.ReleaseMouseCapture();
    }

    private void dragRectangle_MouseMove(object sender, MouseEventArgs e)
    {
        if (!_isRectDragInProg) return;
        // get the position of the mouse relative to the Canvas
        var mousePos = e.GetPosition(Toolbox);

        // center the rect on the mouse
        double left = mousePos.X - (dragRectangle.ActualWidth / 2);
        double top = mousePos.Y - (dragRectangle.ActualHeight / 2);
        Canvas.SetLeft(dragRectangle, left);
        Canvas.SetTop(dragRectangle, top);
    }

    private void mainCanvas_DragEnter(object sender, DragEventArgs e)
    {
        string t = "Test";  // Never enters this event
    }

    private void mainCanvas_DragLeave(object sender, DragEventArgs e)
    {
        string t = "Test";  // Never enters this event
    }

    private void mainCanvas_PreviewDragEnter(object sender, DragEventArgs e)
    {
        string t = "Test";  // Never enters this event
    }

    private void mainCanvas_PreviewDragLeave(object sender, DragEventArgs e)
    {
        string t = "Test";  // Never enters this event
    }

    private void mainCanvas_Drop(object sender, DragEventArgs e)
    {
        string t = "Test";  // Never enters this event
    }
}

}


Solution

  • You're not dragging anything actually, just moving rectangle here and there in canvas.

    You'll need to call DragDrop.DoDragDrop function when your rectangle leave the source, also detach it from source so that you can add it to target later.

        // Drag - In mousemove event when mouse has gone out of toolbox
        DragDrop.DoDragDrop(
            Toolbox, 
            new DataObject("MyWPFObject", rectangle),
            DragDropEffects.Move
        );
    
        // Drop - In Drop event of target
        if (e.Data.GetDataPresent("MyWPFObject"))
        { 
           var rectangle = e.Data.GetData("MyWPFObject") as Rectangle
        ....
    

    Tutorial ...