恒定长宽比 [英] Constant Aspect Ratio

查看:131
本文介绍了恒定长宽比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用SizeChanged事件时,似乎要对嵌套事件进行空洞更改.有办法防止这种情况吗?

When using the SizeChanged event it seems like you set off a hole change of nested events.  Is there a way to prevent this?

已经多次询问了有关如何调整窗口大小并使窗口保持恒定纵横比的问题.我到过几个地方,但找不到很好的解决方案.它们主要是解决SizeChanged问题的解决方案 事件.

The question has been asked several times about how to resize a window and keep it at a constant aspect ratio.  I have looked several places and not found a good solution.  They are mostly kludgy solutions to get around the problems with the SizeChanged event.

以下是保持纵横比恒定的简单解决方案.请注意,我尝试跳过不需要的事件,直到第一个事件完成为止.这有点奏效,但不是全部.

Following is a simple solution to keeping the aspect ratio constant.  Note I tried to skip unwanted events until the first one finishes.  It sort of works but not totally.

    public partial class MainWindow : Window
    {
        double myHeightStart;
        double myWidthStart;
        double myHeightLast;
        double myWidthLast;
        double myAspectRatio;
        bool blLoad_SizeChange_Event = true;
        bool blRun_Event = true;

        public MainWindow()
        {
            InitializeComponent();
            myHeightStart = myWindow.Height;
            myWidthStart = myWindow.Width;
            myAspectRatio = myHeightStart / myWidthStart;
            SetLast();

        }

        private void myWindow_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (blRun_Event)
            {
                blRun_Event = false;
                if (blLoad_SizeChange_Event)
                {
                    blLoad_SizeChange_Event = false;
                }
                else
                {
                    double myHeightNew = myWindow.Height;
                    double myWidthNew = myWindow.Width;

                    if (myHeightNew != myHeightLast)
                    {
                        myWindow.Width = myWindow.ActualHeight / myAspectRatio;
                        SetLast();
                    }
                    else if (myWidthNew != myWidthLast)
                    {
                        myWindow.Height = myWindow.ActualWidth * myAspectRatio;
                        SetLast();
                    }
                }
                blRun_Event = true;
            }
        }

        private void SetLast()
        {
            myHeightLast = myWindow.Height;
            myWidthLast = myWindow.Width;
        }

    }

推荐答案

adabyron在Stackoverflow上提供的解决方案似乎效果很好:

The solution provided by adabyron on Stackoverflow seems to work very well: http://stackoverflow.com/questions/2471867/resize-a-wpf-window-but-maintain-proportions

我已经对其进行了测试:

I have tested it:


ConstantAspectRatioWindow.xaml.cs:

using System;
using System.Runtime.InteropServices;
using System.Windows;
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;
        }
    }

}


ConstantAspectRatioWindow.xaml:

<Window x:Class="WpfApplication1.ConstantAspectRatioWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication9"
        mc:Ignorable="d"
 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>

希望有帮助.

请记住,通过将有用的帖子标记为答案来关闭话题,然后在遇到新问题时开始新话题.请不要在同一线程中问几个问题.

Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.


这篇关于恒定长宽比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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