I need to keep the aspect ratio of my WPF window when it gets resized. Only solution I have found to solve the aspect ratio was to use the following WINAPI code and register the Window to the WindowAspectRatio class in the Window_SourceInitialized event handler.
The Window_SourceInitialized event handler.
private void Window_SourceInitialized(object sender, EventArgs e)
{
ratio = WindowAspectRatio.Register((Window)sender);
double scaleOfScreen = 0.5;
double w = (double)WpfScreen.GetScreenFrom(this).WorkingArea.Width;
double h = (double)WpfScreen.GetScreenFrom(this).WorkingArea.Height;
if (w < h)
{
Application.Current.MainWindow.Width = w * scaleOfScreen;
Application.Current.MainWindow.Height = w * scaleOfScreen / ratio;
}
else
{
Application.Current.MainWindow.Height = h * scaleOfScreen;
Application.Current.MainWindow.Width = h * ratio * scaleOfScreen;
}
this.InvalidateVisual();
}
The WindowAspectRatio class
internal class WindowAspectRatio
{
private double ratio_;
private Window windowToTrack_;
private WindowAspectRatio(Window window)
{
ratio_ = window.Width / window.Height;
windowToTrack_ = window;
((HwndSource)HwndSource.FromVisual(window)).AddHook(DragHook);
}
public static double Register(Window window)
{
return new WindowAspectRatio(window).ratio_;
}
internal enum WM
{
WINDOWPOSCHANGING = 0x0046,
}
[Flags()]
public enum SWP
{
NoMove = 0x2,
}
[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;
}
private IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
{
if ((WM)msg == WM.WINDOWPOSCHANGING)
{
WINDOWPOS position = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
if ((position.flags & (int)SWP.NoMove) != 0 ||
HwndSource.FromHwnd(hwnd).RootVisual == null) return IntPtr.Zero;
double screenW = (double)WpfScreen.GetScreenFrom(windowToTrack_).WorkingArea.Width;
double screenH = (double)WpfScreen.GetScreenFrom(windowToTrack_).WorkingArea.Height;
if (position.cy >= screenH)
position.cy = (int)screenH;
position.cx = (int)(position.cy * ratio_);
if (position.cx >= screenW)
{
position.cx = (int)screenW;
position.cy = (int)(position.cx / ratio_);
}
Marshal.StructureToPtr(position, lParam, true);
handeled = true;
}
return IntPtr.Zero;
}
This works well. When resizing the window by dragging in a Window corner, it works just perfect and aspect ratio is kept.
If I move the mouse pointer to the bottom edge of the window, where one would resize the Window's height, it works fine too to drag that edge. The Window is resized and aspect ratio is still kept.
Problem is when moving the mouse pointer to the left Window edge I get the resize mouse pointer icon, but when trying to resize the window, the window now instead just moves horizontally.
Also when moving the mouse pointer to the right Window edge I get the resize mouse pointer icon, but when trying to resize nothing happens at all.
For me it would be no problem to live with that only resizing by the corner would work if one could just prevent the the resize mouse pointer icon to show up when trying to resize horizontally (by left or right edge) or vertical only (by bottom edge), allowing only a resize by grabbing the window's corner. So the question, is it possible to somehow prevent the horizontal and vertical resize mouse pointer icons but still allow the resize (vertically and horizontally) at the same time by grabbing the corner?
Alternatively, if someone has an idea how one could resolve the problem of horizontal resizing not working as expected using the code above that would also solve the problem.