Rob L
Rob L

Reputation: 2372

WPF SkiaSharp Canvas Click Mouse position

Note: This is a C# SkiaSharp WPF application.

When I repaint my SKCanvas (which is the full width of my app), I record the width and height. Ignore height for now. On a 4K monitor the width is recorded correctly 3840 pixels (when maximised).

When I click on the canvas far left, the mouse X position recorded is almost zero as expected.

However, when I click on the far right of the canvas 2552 is given as the X position, not something near 3840 as I expected?

This is the code I use to get the mouse position when it is clicked.

private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var pixelPosition = e.GetPosition(sender as SKElement);
    // ...
}

and my XAML:

<skia:SKElement
    Name="MyCanvas"
    PaintSurface="MyCanvas_PaintSurface"
    MouseLeftButtonDown="MyCanvas_MouseLeftButtonDown"
    />

I also checked the width/height in the SizeChanged event of MyCanvas and that does NOT report 3840 either, it reports 2552 as the width?

Any ideas why the reported width is 2552 whereas the actual width is 3840?

Upvotes: 0

Views: 1516

Answers (1)

thatguy
thatguy

Reputation: 22089

As @Leandro pointed out your DPI scaling is 150%. You can get the DPI scale in .NET Framework >= 4.6.2 and .NET Core >= 3.0 with the GetDpi method of VisualTreeHelper. It returns a DpiScale struct that contains the scale horizontal and vertical DPI scale factors.

private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
   var mainWindow = Application.Current.MainWindow;
   var dpiScale = VisualTreeHelper.GetDpi(mainWindow);

   var dpiScaleX = dpiScale.DpiScaleX;
   var dpiScaleY = dpiScale.DpiScaleY;

   var pixelPosition = e.GetPosition(sender as Canvas);
   var scaledPixelPosition = new System.Windows.Point(pixelPosition.X * dpiScaleX, pixelPosition.Y * dpiScaleY);

   // ...your code.
}

If you are working with a lower version of a framework without GetDpi, you can use this instead.

var mainWindow = Application.Current.MainWindow;

Matrix m = PresentationSource.FromVisual(mainWindow).CompositionTarget.TransformToDevice;
var dpiScaleX = m.M11;
var dpiScaleY = m.M22;

Upvotes: 1

Related Questions