Как рассчитать положение элемента управления на экране (в пикселях) в WinUI 3C#

Место общения программистов C#
Ответить
Anonymous
 Как рассчитать положение элемента управления на экране (в пикселях) в WinUI 3

Сообщение Anonymous »

Моя цель — вычислить положение левого края среднего блока на экране. Это используется для позиционирования плавающего окна точно вдоль левого края.
Проблема в том, что значение, которое я получаю при вычислении положения экрана, не соответствует ожидаемому. Это тестовое приложение показывает расчетное положение «От экрана» и фактическое положение плавающих окон на экране при перетаскивании на место.

Изображение
Расчеты координат в приложении Windows
Под «ControlBlock» указана ширина ControlBlock а «Позиция окна» — это координаты экрана, рассчитанные с помощью:
//Application window position
var mainWindow = (Application.Current as App) ? ._window;
PointInt32 windowPos = mainWindow.AppWindow.Position;

//Get monitor from a window
IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(mainWindow);
IntPtr hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

//Control block
WindowPos.Text = $ "Window Pos: ({windowPos.X:N0}, {windowPos.Y:N0})";
ControlBlockWidth.Text = $ "Width: {ControlBlock.ActualWidth:N0}";

Ниже «LeftBlock» указана ширина LeftBlock, а «LeftBlock Screen» — неправильно рассчитанное положение левого края LeftBlock на экране:
//Left block
LeftBlockWidth.Text = $ "Width: {LeftBlock.ActualWidth:N0}";

var transformLeftBlock = LeftBlock.TransformToVisual(mainWindow.Content as UIElement);
var pointLeftBlock = transformLeftBlock.TransformPoint(new Point(0, 0));

LeftBlockScreenCoord.Text = $ "LeftBlock Screen: ({pointLeftBlock.X + windowPos.X:N0}, {pointLeftBlock.Y + windowPos.Y:N0})";

Ниже MiddleBlock рассчитываются различные значения: (Наиболее интересным является «С экрана», его значение X должно быть таким же, как показано в «Позиции экрана» плавающего окна).
//Middle block
var transform = MiddleBlock.TransformToVisual(LeftBlock);
var pointInRoot = transform.TransformPoint(new Point(0, 0));
MiddleBlockFromLeftBlock.Text = $ "From LeftBlock: ({pointInRoot.X:N0}, {pointInRoot.Y:N0})";

var transform2 = MiddleBlock.TransformToVisual(RootGrid);
var pointInRoot2 = transform2.TransformPoint(new Point(0, 0));
MiddleBlockFromRootGrid.Text = $ "From RootGrid: ({pointInRoot2.X:N0}, {pointInRoot2.Y:N0})";

var transform3 = MiddleBlock.TransformToVisual(mainWindow.Content as UIElement);
var pointInRoot3 = transform3.TransformPoint(new Point(0, 0));
MiddleBlockWindowCoord.Text = $ "From AppWindow: ({pointInRoot3.X:N0}, {pointInRoot3.Y:N0})";

MiddleBlockScreenCoord.Text = $ "From Screen: ({pointInRoot3.X + windowPos.X:N0}, {pointInRoot3.Y + windowPos.Y:N0})";

Плавающие окна позиционируются по координатам экрана
Плавающие окна перетаскиваются в нужное положение, а «Положение экрана» — это значение «floatingWindow.AppWindow.Position».
Я также могу указать точные координаты экрана, которые затем позиционируют плавающее окно с помощью «floatingWindow.AppWindow.Move(new) PointInt32(targetX, targetY))»
Если я расположим плавающее окно ближе к правой стороне экрана, координата X будет равна 3397 + ширина окна (500), что близко к разрешению экрана (3840x2160).
Коэффициент масштабирования между виртуальным разрешением и реальным разрешением
Я попытался получить коэффициент масштабирования, который обсуждался в этом вопросе, но это 1.0.
Как определить текущее разрешение экрана?
Вопрос
Кто-нибудь знает, как правильно рассчитать положение левого края экрана MiddleBlock? Очевидно, что координаты внутри приложения не являются пикселями. Нужно ли какое-либо преобразование для перехода от координат приложения к координатам экрана?
Добавлено
Минимальная версия, содержащая только основную часть:
MinimalVersionPage.xaml



























MinimalVersionPage.xaml.cs
public sealed partial class MinimalVersionPage : Page
{
public MinimalVersionPage()
{
InitializeComponent();
}

private void UpdateCoordsButton_Click(object sender, RoutedEventArgs e)
{
//Application window position
var mainWindow = (Application.Current as App)?._window;
PointInt32 windowPos = mainWindow.AppWindow.Position;

//Left block
WindowPos.Text = $"Window Pos: ({windowPos.X:N0}, {windowPos.Y:N0})";
LeftBlockWidth.Text = $"Width: {LeftBlock.ActualWidth:N0}";

//Middle block
var transform3 = MiddleBlock.TransformToVisual(mainWindow.Content as UIElement);
var pointInRoot3 = transform3.TransformPoint(new Point(0, 0));
MiddleBlockWindowCoord.Text = $"From AppWindow: ({pointInRoot3.X:N0}, {pointInRoot3.Y:N0})";

MiddleBlockScreenCoord.Text = $"From Screen: ({pointInRoot3.X + windowPos.X:N0}, {pointInRoot3.Y + windowPos.Y:N0})";
}

private void CreateWindow_Click(object sender, RoutedEventArgs e)
{
var floatingWindow = new Window
{
Title = "Floating Window"
};

floatingWindow.AppWindow.Resize(new Windows.Graphics.SizeInt32(500, 700));

var presenter = floatingWindow.AppWindow.Presenter as Microsoft.UI.Windowing.OverlappedPresenter;
if (presenter != null)
{
presenter.IsAlwaysOnTop = true;
}

var stackPanel = new StackPanel
{
Padding = new Thickness(20),
Spacing = 10
};

var coordinateText = new TextBlock
{
Text = "Screen Position: (0, 0)",
FontSize = 16,
HorizontalAlignment = HorizontalAlignment.Center
};

stackPanel.Children.Add(coordinateText);

floatingWindow.Content = stackPanel;

// Set up a timer to update the coordinates every 16 milliseconds (~60 FPS)
var dispatcherQueue = floatingWindow.DispatcherQueue;
var timer = dispatcherQueue.CreateTimer();

timer.Interval = TimeSpan.FromMilliseconds(16);
timer.IsRepeating = true;
timer.Tick += (s, args) =>
{
var position = floatingWindow.AppWindow.Position;
var size = floatingWindow.AppWindow.Size;
coordinateText.Text = $"Screen Position: ({position.X}, {position.Y})";
};

floatingWindow.Closed += (s, args) =>
{
timer.Stop();
};

timer.Start();
floatingWindow.Activate();
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... in-winui-3
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»