调整 WPF 窗口的大小,但保持比例? [英] Resize a WPF window, but maintain proportions?

查看:46
本文介绍了调整 WPF 窗口的大小,但保持比例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用户可调整大小的 WPF 窗口,我想限制调整大小,以便窗口的纵横比保持不变.

I have a user resizable WPF Window that I want to constrain the resizing so the aspect ratio of the window stays constant.

理想情况下,我希望在调整窗口大小时通过将角拖动到保持适当纵横比的位置来限制鼠标位置.如果用鼠标调整一个边缘的大小,另一个维度应该同时改变.

Ideally I would like to constrain mouse location when the window is being resized by dragging a corner to positions that maintain the proper aspect ration. If an edge is resized with the mouse, the other dimension should change at the same time.

有没有简单的方法可以做到这一点,或者有谁知道的好的在线示例?

Is there a simple way to do this or a good on-line example that anyone knows of?

如果没有更好的解决方案,我会在我稍微改进后发布我所做的.

If no better solutions come up, I'll post what I've done after I've refined it a bit.

推荐答案

我在 Nir ​​这里找到了一个很好的答案.还是有一些瑕疵,基本上是在右上角、右下角和底边调整大小就可以了,其他边和角就不行了.好的一面是,纵横比一直保持平滑.

I've found a good answer by Nir here. There are still some flaws, basically resizing in top right corner, bottom right corner and bottom side will be fine, other sides and corners are not. The bright side is, the aspect ratio is smoothly kept all the time.

我找到了一种方法来消除大部分问题.开始调整大小时,将通过定位鼠标相对于窗口的位置来确定将被人为调整以保持纵横比的尺寸.我发现的唯一剩余缺陷是从角落(右下角除外)调整大小时窗口的位置可能会改变.

I found a way to remove most of the problems. When sizing starts, the dimension that will be artificially adjusted to keep the aspect ratio is determined by locating the mouse position relative to the window. The only remaining imperfections I found are that the position of the window may change when resizing from the corners (except bottom right).

xml:

<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>

背后的代码:

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;
        }
    }
}

这篇关于调整 WPF 窗口的大小,但保持比例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆