Окно WPF скрывает горизонтальные и вертикальные значки размера указателя мыши - PullRequest
0 голосов
/ 24 сентября 2018

Мне нужно сохранить соотношение сторон моего окна WPF, когда оно будет изменено.Единственное решение, которое я нашел для решения соотношения сторон, - это использовать следующий код WINAPI и зарегистрировать Window в классе WindowAspectRatio в обработчике событий Window_SourceInitialized.

Обработчик событий Window_SourceInitialized.

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

Класс WindowAspectRatio

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

Это хорошо работает.При изменении размера окна путем перетаскивания в углу окна оно работает просто идеально, а соотношение сторон сохраняется.

Если я переместлю указатель мыши к нижнему краю окна, где можно изменить размер окна, онтоже отлично работает, чтобы перетащить этот край.Размер окна изменяется, а соотношение сторон по-прежнему сохраняется.

Проблема заключается в том, что при перемещении указателя мыши к левому краю окна появляется значок изменения размера указателя мыши, но при попытке изменить размер окна теперь вместо окна простоперемещается горизонтально.

Также при перемещении указателя мыши к правому краю окна я получаю значок указателя мыши с измененным размером, но при попытке изменить размер ничего не происходит вообще.

Для меня это было бы непроблема, связанная с тем, что изменение размера только по углу сработало бы, если бы можно было просто предотвратить отображение значка указателя мыши при изменении размера по горизонтали (по левому или правому краю) или только по вертикали (по нижнему краю), позволяя толькоизменить размер, схватив угол окна.Таким образом, вопрос, возможно ли как-то предотвратить горизонтальное и вертикальное изменение размеров значков указателя мыши, но при этом разрешить изменение размера (по вертикали и по горизонтали) одновременно, захватывая угол?

В качестве альтернативы, если у кого-то есть идеякак можно решить проблему горизонтального изменения размера, не работающую должным образом, используя приведенный выше код, который также решил бы проблему.

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Хорошо, я нашел простое решение.Кто-то решил эту проблему также на основе подхода WINAPI, позволяющего изменять размеры всех границ, сохраняя соотношение сторон.Основная часть решения ниже.

public partial class MainWindow : Window
    {
        private double _aspectRatio;
        private bool? _adjustingHeight = null;

        public MainWindow()
        {
            InitializeComponent();
            this.SourceInitialized += Window_SourceInitialized;
        }

        private void Window_SourceInitialized(object sender, EventArgs ea)
        {
            HwndSource hwndSource = (HwndSource)HwndSource.FromVisual((Window)sender);
            hwndSource.AddHook(DragHook);

            _aspectRatio = this.Width / this.Height;
        }



        internal enum SWP
        {
            NOMOVE = 0x0002
        }
        internal enum WM
        {
            WINDOWPOSCHANGING = 0x0046,
            EXITSIZEMOVE = 0x0232,
        }

        [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()
        {
            Win32Point w32Mouse = new Win32Point();
            GetCursorPos(ref w32Mouse);
            return new Point(w32Mouse.X, w32Mouse.Y);
        }

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

    }
0 голосов
/ 24 сентября 2018

Тем временем мне удалось предотвратить изменение размеров только по горизонтали / вертикали, изменив код WINAPI следующим образом.Если бы можно было просто запретить значку указателя мыши отображать значки изменения размера внизу, слева и справа по краям окна, у меня было бы приемлемое решение.

    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 (Math.Abs(position.cx - windowToTrack_.Width) < Math.Abs(position.cy - windowToTrack_.Height))
            {
                if (position.cx >= screenW)
                    position.cx = (int)screenW;
                position.cy = (int)(position.cx / ratio_);
                if (position.cy >= screenH)
                    position.cy = (int)screenH;
                position.cx = (int)(position.cy * ratio_);
            }
            else
            {
                if (
                    (position.cx < windowToTrack_.Width &&
                    position.cy == windowToTrack_.Height )
                    ||
                    (position.cx > windowToTrack_.Width &&
                    position.cy == windowToTrack_.Height )
                    )
                {
                    handeled = true;
                    position.x = (int)windowToTrack_.Left;
                    position.y = (int)windowToTrack_.Top;
                    position.cx = (int)windowToTrack_.Width;
                    position.cy = (int)windowToTrack_.Height;
                    Marshal.StructureToPtr(position, lParam, true);
                    return IntPtr.Zero;
                }

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