He encontrado una buena respuesta por Nir here. Todavía hay algunos defectos, básicamente cambiar el tamaño en la esquina superior derecha, la esquina inferior derecha y el lado inferior estará bien, otros lados y las esquinas no lo son. El lado positivo es que la relación de aspecto se mantiene suavemente todo el tiempo.
EDIT: Encontré una manera de eliminar la mayoría de los problemas. Cuando comienza el dimensionamiento, la dimensión que se ajustará artificialmente para mantener la relación de aspecto se determina ubicando la posición del mouse relativa a la ventana. Las únicas imperfecciones que encontré son que la posición de la ventana puede cambiar al cambiar el tamaño de las esquinas (excepto en la esquina inferior derecha).
xaml:
<Window x:Class="WpfApplication1.ConstantAspectRatioWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ConstantAspectRatioWindow" MinHeight="100" MinWidth="150" SizeToContent="WidthAndHeight">
<Grid>
<Border Width="300" Height="200" Background="Navy"/>
<Border Width="150" Height="100" Background="Yellow" />
</Grid>
</Window>
Código atrás:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace WpfApplication1
{
public partial class ConstantAspectRatioWindow : Window
{
private double _aspectRatio;
private bool? _adjustingHeight = null;
internal enum SWP
{
NOMOVE = 0x0002
}
internal enum WM
{
WINDOWPOSCHANGING = 0x0046,
EXITSIZEMOVE = 0x0232,
}
public ConstantAspectRatioWindow()
{
InitializeComponent();
this.SourceInitialized += Window_SourceInitialized;
}
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
public static Point GetMousePosition() // mouse position relative to screen
{
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
return new Point(w32Mouse.X, w32Mouse.Y);
}
private void Window_SourceInitialized(object sender, EventArgs ea)
{
HwndSource hwndSource = (HwndSource)HwndSource.FromVisual((Window)sender);
hwndSource.AddHook(DragHook);
_aspectRatio = this.Width/this.Height;
}
private IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch ((WM)msg)
{
case WM.WINDOWPOSCHANGING:
{
WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
if ((pos.flags & (int)SWP.NOMOVE) != 0)
return IntPtr.Zero;
Window wnd = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
if (wnd == null)
return IntPtr.Zero;
// determine what dimension is changed by detecting the mouse position relative to the
// window bounds. if gripped in the corner, either will work.
if (!_adjustingHeight.HasValue)
{
Point p = GetMousePosition();
double diffWidth = Math.Min(Math.Abs(p.X - pos.x), Math.Abs(p.X - pos.x - pos.cx));
double diffHeight = Math.Min(Math.Abs(p.Y - pos.y), Math.Abs(p.Y - pos.y - pos.cy));
_adjustingHeight = diffHeight > diffWidth;
}
if (_adjustingHeight.Value)
pos.cy = (int)(pos.cx/_aspectRatio); // adjusting height to width change
else
pos.cx = (int)(pos.cy * _aspectRatio); // adjusting width to heigth change
Marshal.StructureToPtr(pos, lParam, true);
handled = true;
}
break;
case WM.EXITSIZEMOVE:
_adjustingHeight = null; // reset adjustment dimension and detect again next time window is resized
break;
}
return IntPtr.Zero;
}
}
}
ver si esto ayuda: http: // stackoverflow.com/questions/288954/how-do-i-keep-aspect-ratio-on-scalable-scrollable-content-in-wpf –