0

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

}

Community
  • 1
  • 1

2 Answers2

2

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

Code0987
  • 2,598
  • 3
  • 33
  • 51
  • Thank you for your quick answer. I have not gotten it to work with what I really want (my example is very simple). It seems that I must make a lot of code myself. But your easy explanation was very good in making me understand a lot more about what constitutes a drag and drop (in WPF). For this, I thank you. – Ragulf Pickaxe Jul 06 '12 at 12:45
0

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

Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Hi Rachel, Thank you for your answer. I do not understand the panel mentionend in your 3rd point. Do you mean rectangle, or is there some panel required that I do not know about? Also your 2nd point: Have your application capture the mouse: Do you have some example? I do not knwo what you mean here. In the real programme, I am creating an object which looks the same, but has its own events, and it is this object that I am dragging and dropping (but only if it lands on the right canvas, otherwise it should dissapear). – Ragulf Pickaxe Jul 06 '12 at 12:50
  • @user1497953 Sorry, that should be `Rectangle` not `Panel`. I'll update it. Also your current code has the dragged `Rectangle` capturing the mouse so any mouse events get handled by the `Rectangle` object only. I was looking through some of my old code, and I have one with all the mouse capture statements commented out, and another one using `e.MouseDevice.Capture(this as IInputElement);` where `e` is `MouseEventArgs` from a `MouseMove` event, and `this` being `Application.Current.MainWindow` – Rachel Jul 06 '12 at 13:03
  • Hi again, I have only been using the events in their default way - therefore I am not able to glean the right structure from what you have written. Do you (or any) know of some references on how to capture events in another context? (Escalating events?) I would still want to be able to get the single moved element amongst numerous elements that might be identical (and overlapping the dragged element). Thank you again. – Ragulf Pickaxe Jul 09 '12 at 13:23
  • @user1497953 I started with [Bea Stollnitz's article on dragging/dropping databound items](http://bea.stollnitz.com/blog/?p=53). I'd highly recommend you check it out - perhaps it can point you to your solution. – Rachel Jul 09 '12 at 13:55