0

I'm attempting to perform a drag and drop operation in WPF. I distinctly remember the days when I did this sort of thing regularly.

I'm using a p/invoke of GetCursorPos() to return screen coordinates. This number is offset from the cursor by quite a bit.

I assumed the issue was scaling due to my laptop's high-DPI setting (120) so I used the following code (stolen from this answer):

private Point ConvertPixelsToUnits(int x, int y)
{
// get the system DPI
IntPtr dDC = GetDC(IntPtr.Zero); // Get desktop DC
int dpi = GetDeviceCaps(dDC, 88);
bool rv = ReleaseDC(IntPtr.Zero, dDC);

// WPF's physical unit size is calculated by taking the 
// "Device-Independant Unit Size" (always 1/96)
// and scaling it by the system DPI
double physicalUnitSize = (1d / 96d) * (double)dpi;
Point wpfUnits = new Point(physicalUnitSize * (double)x,
    physicalUnitSize * (double)y);

return wpfUnits;          
}

While the dpi value is correct from the p/invokes,, the result is way, way off (significantly worse than using the raw GetCursorPos() value).

So after lots of playing around with all the different options I can find, I am at a loss as to how to get the correct values on the Window.

dansan
  • 465
  • 5
  • 16
  • In WPF for any drag and drop, wouldn't you have MouseLeftButtonUp or MouseLeftButtonDown where you would have MouseButtonEventArgs e to obtain the coordinates of `e.GetPosition(yourControl).X` and `e.GetPosition(yourControl).Y` ? – KMC Mar 25 '18 at 16:04
  • I definitely have the initial position; but this is during the GiveFeedback() process. In this, you only have static methods because the DoDragDrop() method suspends other events (or locks the thread or some other magic). – dansan Mar 25 '18 at 16:08
  • I just noticed that I can get it to work by maximizing the main window and then translating the point from GetCursorPos() using MainWindow.PointFromScreen(p). But I don't really understand why. – dansan Mar 25 '18 at 16:09
  • You should probably be using a behavior or attached property to solve this.p/invoke is not required, is it? – Dennis Kuypers Mar 25 '18 at 16:31
  • @DennisKuypers, you're not wrong about how if I were going to re-use this, an attached behavior is the right way to go; that has nothing to do with the question though. – dansan Mar 25 '18 at 16:38
  • I wouldn't have thought p/invoke is necessary. I'd probably use a behaviour to encapsulate code but at the end of the day you'd have event handlers. If this is the one bit of drag drop in an app then that encapsulation is a bit academic. – Andy Mar 25 '18 at 16:38
  • I have a drag drop alternative which might be worth mentioning. I put a usercontrol in a thumb and the user drags it on a canvas. It can start outside the canvas because of the non clipping weirdness of canvas. Drag is smoother and I easily have a complex usercontrol on screen. This is how you drag units onto the map from the treeview in the scenario editor: https://imgur.com/4n7vH8k I wait until they stop moving the piece until checking it's on the board or valid terrain. Not sure if that's any good to you though. – Andy Mar 25 '18 at 16:42

1 Answers1

0

I can make it work with the following, but I'm hoping someone can provide a good explanation:

var transform = PresentationSource.FromVisual(PacksApp.Current.MainWindow).CompositionTarget.TransformFromDevice;
var pointOfMouse = transform.Transform(GetCursorPos());
dansan
  • 465
  • 5
  • 16