Cha*_*ler 14 windows wpf resize aspect-ratio
我有一个用户可调整大小的WPF窗口,我想约束调整大小,以便窗口的宽高比保持不变.
理想情况下,我想在调整窗口大小时通过将角落拖动到保持正确宽高比的位置来约束鼠标位置.如果使用鼠标调整边缘大小,则另一个维度应同时更改.
有没有一种简单的方法可以做到这一点或一个人们都知道的好的在线示例?
如果没有更好的解决方案出现,我会在我稍微改进之后发布我所做的事情.
Mik*_*chs 20
尼尔在这里找到了一个很好的答案.还有一些瑕疵,基本上在右上角调整大小,右下角和底边都会很好,其他的边角都没有.亮点是,纵横比一直保持平稳.
编辑:我找到了一种方法来消除大多数问题.当开始调整大小时,将通过相对于窗口定位鼠标位置来确定将人为调整以保持宽高比的尺寸.我发现的唯一剩余缺陷是,当从角落调整大小时(右下方除外),窗口的位置可能会发生变化.
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>
Run Code Online (Sandbox Code Playgroud)
代码背后:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这并不强制窗口具有特定的比例(正如OP所要求的),但我已经设法通过将内容包装在 a 中并Viewbox设置拉伸特性为Stretch="Uniform". 不需要隐藏代码。
WPF:
<Viewbox Name="MainViewbox" Stretch="Uniform">
... your content here
</Viewbox>
Run Code Online (Sandbox Code Playgroud)
这是否有效:
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) {
if (sizeInfo.WidthChanged) this.Width = sizeInfo.NewSize.Height * aspect;
else this.Height = sizeInfo.NewSize.Width / aspect;
}
Run Code Online (Sandbox Code Playgroud)
在这里找到的。