如何才能在WPF窗口中仅允许统一resize?

我不希望我的窗口“仅水平”或“仅垂直”resize。 我可以在我的窗口上设置一个可以强制执行此操作的属性,还是有一个可以使用的漂亮的代码隐藏技巧?

您可以使用WPF的ViewBox保留内容的宽高比,并使用固定宽度和高度的控件。

让我们试一试。 您可以更改ViewBox的“Stretch”属性以体验不同的结果。

这是我的screeen镜头: 在此处输入图像描述

       

您始终可以处理WM_WINDOWPOSCHANGING消息,这可以让您在resize过程中控制窗口大小和位置(而不是在用户完成大小调整后修复内容)。

以下是您在WPF中的操作方法,我将来自多个源的代码组合在一起,因此可能会出现一些语法错误。

 internal enum WM { WINDOWPOSCHANGING = 0x0046, } [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 void Window_SourceInitialized(object sender, EventArgs ea) { HwndSource hwndSource = (HwndSource)HwndSource.FromVisual((Window)sender); hwndSource.AddHook(DragHook); } private static IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled) { 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; } bool changedPos = false; // *********************** // Here you check the values inside the pos structure // if you want to override tehm just change the pos // structure and set changedPos to true // *********************** if (!changedPos) { return IntPtr.Zero; } Marshal.StructureToPtr(pos, lParam, true); handeled = true; } break; } return IntPtr.Zero; } 

这就是我的解决方案。

您需要将其添加到控件/窗口标记中:

 Loaded="Window_Loaded" 

你需要将它放在你的代码中:

 private double aspectRatio = 0.0; private void Window_Loaded(object sender, RoutedEventArgs e) { aspectRatio = this.ActualWidth / this.ActualHeight; } protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) { if (sizeInfo.WidthChanged) { this.Width = sizeInfo.NewSize.Height * aspectRatio; } else { this.Height = sizeInfo.NewSize.Width * aspectRatio; } } 

我尝试了Viewbox技巧,但我不喜欢它。 我想将窗口边框锁定到特定大小。 这是在窗口控件上测试的,但我认为它也适用于边框。

您可以尝试复制我经常在Flash Video网站上看到的效果。 它们允许您以任何方式扩展浏览器窗口,但只能拉伸显示区域以使其适合最小的高度或宽度。

例如,如果垂直拉伸窗口,则应用程序不会resize。 只需在显示区域的顶部和底部添加黑条,并保持垂直居中。

WPF可能会或可能不会这样; 我不知道。

这可能有点迟了但你可以简单地把它放在你的代码背后….

 Private Sub UserControl1_SizeChanged(ByVal sender As Object, ByVal e As System.Windows.SizeChangedEventArgs) Handles Me.SizeChanged If e.HeightChanged Then Me.Width = Me.Height Else Me.Height = Me.Width End If End Sub 

我原本以为你可以使用值转换器将宽度双向绑定到高度以保持纵横比。 将纵横比作为转换器参数传递将使其更通用。

所以,我试过这个 – 首先没有转换器的绑定:

   Width:  Height:    

奇怪的是,绑定的行为就好像它是单向的,并且报告的窗口宽度(如TextBlock中所示)与屏幕上的大小不一致!

这个想法可能值得追求,但这种奇怪的行为需要首先解决。

希望有所帮助!

在代码示例中:

 if (sizeInfo.WidthChanged) { this.Width = sizeInfo.NewSize.Height * aspectRatio; } else { this.Height = sizeInfo.NewSize.Width * aspectRatio; } 

我相信第二个计算应该是:

 this.Height = sizeInfo.NewSize.Width * (1/aspectRatio); 

我在“SizeChanged”事件处理程序中对此工作进行了修改。 因为我希望宽度是控制尺寸,所以我只是通过计算forms强制高度与它匹配:

 if (aspectRatio > 0) // enforce aspect ratio by restricting height to stay in sync with width. this.Height = this.ActualWidth * (1 / aspectRatio); 

您可能会注意到aspectRatio> 0的检查,…我这样做是因为我发现在“Load”方法甚至分配了aspectRatio之前,它倾向于调用我的处理程序进行resize。

也许为时已晚,但我找到了Mike O’Brien博客的解决方案,而且效果非常好。 http://www.mikeobrien.net/blog/maintaining-aspect-ratio-when-resizing/以下是他博客中的代码:

  ... Window> public partial class Main : Window { private void Window_SourceInitialized(object sender, EventArgs ea) { WindowAspectRatio.Register((Window)sender); } ... } internal class WindowAspectRatio { private double _ratio; private WindowAspectRatio(Window window) { _ratio = window.Width / window.Height; ((HwndSource)HwndSource.FromVisual(window)).AddHook(DragHook); } public static void Register(Window window) { new WindowAspectRatio(window); } 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; position.cx = (int)(position.cy * _ratio); Marshal.StructureToPtr(position, lParam, true); handeled = true; } return IntPtr.Zero; } }