0
votes

I want to get the mouse position when the mouse moves while dragging.

Here is my minimal not working example:

MainWindow.xaml:

<Window x:Class="WpfApplication8.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Canvas x:Name="_canvas" Background="Green">
        <TextBlock x:Name="_positionTextBlock"/>
        <Rectangle x:Name="_dragSource"
                   Width="20"
                   Height="50"
                   Fill="Blue" 
                   Canvas.Top="150" 
                   Canvas.Left="20" 
                   PreviewMouseDown="DoDrag"/>
        <Rectangle x:Name="_dragTarget"
                   Width="60" 
                   Height="70"
                   Fill="Red" 
                   Canvas.Top="110" 
                   Canvas.Left="300" 
                   AllowDrop="True"/>
    </Canvas>
</Window>

MainWindow.xaml.cs:

using System.Windows;
using System.Windows.Input;

namespace WpfApplication8
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void DoDrag(object sender, MouseButtonEventArgs e)
        {
            DragDrop.DoDragDrop(_dragSource, "abc", DragDropEffects.Move);
        }
    }
}

As you can see: I have a TextBlock called _positionTextBlock which should display the current mouse position while dragging.

Edit (long story): I have a green rectanlge that can be dragged and droped on the red rectangle. My requirement is, to display the mouse position while dragging the green rectangle.

How do I do that?

What I have tried:

changing the constructor of MainWindow to:

public MainWindow()
{
    InitializeComponent();
    DragOver += (s, e) => _positionTextBlock.Text = e.GetPosition(_canvas).ToString();
}

But this only shows the position when the mouse is over the red rectangle.

I also tried:

public MainWindow()
{
    InitializeComponent();
    MouseMove += (s, e) => _positionTextBlock.Text = e.GetPosition(_canvas).ToString();
}

but the MouseMove-Event doesn't fire while dragging

I also tried:

private void DoDrag(object sender, MouseButtonEventArgs ev)
{
    _dragSource.GiveFeedback +=
        (s, e) => _positionTextBlock.Text = Mouse.PrimaryDevice.GetPosition(_canvas).ToString();
    DragDrop.DoDragDrop(_dragSource, "abc", DragDropEffects.Move);
}

but this seems to get the window-position in screen coordinates.

And this is where I got stuck. Does anyone have any idea?

2
Try QueryContinueDrag event.Maximus
I tried, but is has, like GiveFeedback event, no GetPosition()Rico-E

2 Answers

0
votes

Edited using PreviewMouseMove

Second edit: Full sample

XAML:

<Canvas x:Name="_canvas" Background="Green">
    <TextBlock x:Name="_positionTextBlock"/>
    <Rectangle x:Name="_dragSource"
               Width="20"
               Height="50"
               Fill="Blue" 
               Canvas.Top="150" 
               Canvas.Left="20" 
               PreviewMouseMove="DragSourcePreviewMouseMove"/>
    <Rectangle x:Name="_dragTarget"
               Width="60" 
               Height="70"
               Fill="Red" 
               Canvas.Top="110" 
               Canvas.Left="300" 
               AllowDrop="True"/>
</Canvas>

Codebehind:

public MainWindow()
{
    InitializeComponent();
}

private void DragSourcePreviewMouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed)
    {
        _positionTextBlock.Text = e.GetPosition(_canvas).ToString();
    }
    e.Handled = true;
}

Hope this helps.

0
votes

I tried your demo, and found that if you set AllowDrop="True" on the window, the DragOver event works.

If you want to avoid dropping to the window, you can listen the PreviewDragOver event of window. Then set the DragEventArgs.Effect to None and DragEventArgs.Handled to True.

You can also get the mouse position by another way, which works all the time, expect you need a timer to refresh the position regularly.

Visual.PointFromScreen(MousePositionToScreen);

public Point MousePositionToScreen
{
    get
    {
        GetCursorPos(out POINT p);
        return new Point(p.X, p.Y);
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int X;
    public int Y;

    public POINT(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool GetCursorPos(out POINT pt);

Finally, you can try Keith Stein's solution. It's much more complicated.