Ragulf Pickaxe
Ragulf Pickaxe

Reputation: 18

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
    }
}

}

Upvotes: 0

Views: 2981

Answers (2)

Rachel
Rachel

Reputation: 132548

I believe it's because you're capturing the mouse, so all mouse events are being handled by your dragged Rectangle, and they don't get passed on to your Canvas

I personally had all kinds of problems with using WPF's built-in drag/drop functionality, so I ended up using MouseEvents instead.

The solution I used was from this answer, and went like this:

  1. On MouseDown with left button down, record the position (on MouseLeave erase the position)

  2. On MouseMove, if left button down, position is recorded, and current mouse position differs by more than delta, set a flag saying drag operation is in progress & have your application (not the dragged object) capture the mouse

  3. On MouseMove with drag operation in progress, use hit testing to determine where your rectangle should be (ignoring the rectangle itself) and adjust its parenting and position accordingly.

  4. On MouseUp with drag operation in progress, release the mouse capture and clear the "drag operation is in progress" flag

Upvotes: 0

Code0987
Code0987

Reputation: 2618

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 ...

Upvotes: 2

Related Questions