WPF: преобразование между координатами экрана и координатами WPF
Я понимаю, что координаты WPF отличаются от "реальных" экранных координат (координаты пикселей), если компьютер не использует настройку DPI по умолчанию. В моей программе я хочу (1) выяснить, какой монитор окна WPF включен, и (2) открыть другое окно в нижнем левом углу того же монитора. Я слышал, что нет эквивалента Screen для WPF, поэтому я использую версию WinForms, как показано ниже, которая отлично работает в 96 DPI по умолчанию:
public void ChooseInitialPosition(Window w) // w is some other window
{
var scr = System.Windows.Forms.Screen.FromRectangle(
new System.Drawing.Rectangle((int)w.Left, (int)w.Top, (int)w.Width, (int)w.Height))
.WorkingArea;
this.Left = scr.Right - Width;
this.Top = scr.Bottom - Height;
}
Но в других DPI оба действия работают некорректно и могут полностью закрыть окно.
До сих пор, похоже, я могу использовать Visual.PointToScreen для первой части:
var p1 = w.PointToScreen(new Point(0,0));
var p2 = w.PointToScreen(new Point(w.Width,w.Height));
var scr = System.Windows.Forms.Screen.FromRectangle(
new System.Drawing.Rectangle((int)p1.X, (int)p1.Y, (int)(p2.X - p1.X), (int)(p2.Y - p1.Y))).WorkingArea;
Я не уверен, что это совершенно правильно, так как это может неправильно учитывать границы. Но вторая часть важнее. Как преобразовать прямоугольник экрана "scr" в пространство WPF, чтобы правильно установить Left и Top?
Ответы
Ответ 1
-
На каком экране находится окно WPF:
private static Screen GetScreen(Window window)
{
return Screen.FromHandle(new WindowInteropHelper(window).Handle);
}
-
Откройте другое окно в нижнем левом углу того же экрана:
static Point RealPixelsToWpf(Window w, Point p)
{
var t = PresentationSource.FromVisual(w).CompositionTarget.TransformFromDevice;
return t.Transform(p);
}
private static void SetPositionBottomLeftCorner(Window sourceWindow, Window targetWindow)
{
var workingArea = GetScreen(sourceWindow).WorkingArea;
var corner = RealPixelsToWpf(sourceWindow, new Point(workingArea.Left, workingArea.Bottom));
targetWindow.Left = corner.X;
targetWindow.Top = corner.Y - targetWindow.ActualHeight;
}
Ответ 2
Это работает, если вы поместите его в код для вашего окна?
protected override void OnContentRendered(System.EventArgs e)
{
base.OnContentRendered(e);
MoveToLowerRightCorner();
}
private void MoveToLowerRightCorner()
{
var workingArea = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea;
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
var corner = transform.Transform(new Point(workingArea.Right, workingArea.Bottom));
this.Left = corner.X - this.ActualWidth;
this.Top = corner.Y - this.ActualHeight;
}