Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize a WPF Window in increments?

Tags:

c#

.net

wpf

xaml

Is it possible to make a Window such that when it's resized in height by the user, it increments and decrements by 10? Sort of like snapping resize.

like image 624
Joan Venge Avatar asked Dec 17 '22 14:12

Joan Venge


2 Answers

Here is an example of how this can be done:

using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;

namespace DeleteMeWPF {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow {
        public MainWindow() {
            InitializeComponent();
        }

        protected override void OnSourceInitialized(EventArgs e) {
            base.OnSourceInitialized(e);

            IntPtr handle = new WindowInteropHelper(this).Handle;
            HwndSource.FromHwnd(handle).AddHook(new HwndSourceHook(this.WindowProc));
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        private const int WM_SIZING = 0x0214;

        private const int WMSZ_BOTTOM = 6;
        private const int WMSZ_BOTTOMLEFT = 7;
        private const int WMSZ_BOTTOMRIGHT = 8;
        private const int WMSZ_LEFT = 1;
        private const int WMSZ_RIGHT = 2;
        private const int WMSZ_TOP = 3;
        private const int WMSZ_TOPLEFT = 4;
        private const int WMSZ_TOPRIGHT = 5;

        private const int SnappingIncrement = 100;
        private const int SnappingThresholdWidth = 300;
        private const int SnappingThresholdHeight = 400;

        private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
            switch (msg) {
                case WM_SIZING:
                    RECT bounds = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));

                    int width = bounds.right - bounds.left;
                    int height = bounds.bottom - bounds.top;

                    switch (wParam.ToInt32()) {
                        case WMSZ_BOTTOM:
                            if (height > SnappingThresholdHeight)
                                bounds.bottom = bounds.top + ((int)((double)height / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_BOTTOMLEFT:
                            if (height > SnappingThresholdHeight)
                                bounds.bottom = bounds.top + ((int)((double)height / (double)SnappingIncrement) * SnappingIncrement);
                            if (width > SnappingThresholdWidth)
                                bounds.left = bounds.right - ((int)((double)width / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_BOTTOMRIGHT:
                            if (height > SnappingThresholdHeight)
                                bounds.bottom = bounds.top + ((int)((double)height / (double)SnappingIncrement) * SnappingIncrement);
                            if (width > SnappingThresholdWidth)
                                bounds.right = bounds.left + ((int)((double)width / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_LEFT:
                            if (width > SnappingThresholdWidth)
                                bounds.left = bounds.right - ((int)((double)width / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_RIGHT:
                            if (width > SnappingThresholdWidth)
                                bounds.right = bounds.left + ((int)((double)width / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_TOP:
                            if (height > SnappingThresholdHeight)
                                bounds.top = bounds.bottom - ((int)((double)height / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_TOPLEFT:
                            if (width > SnappingThresholdWidth)
                                bounds.left = bounds.right - ((int)((double)width / (double)SnappingIncrement) * SnappingIncrement);
                            if (height > SnappingThresholdHeight)
                                bounds.top = bounds.bottom - ((int)((double)height / (double)SnappingIncrement) * SnappingIncrement);
                            break;
                        case WMSZ_TOPRIGHT:
                            if (width > SnappingThresholdWidth)
                                bounds.right = bounds.left + ((int)((double)width / (double)SnappingIncrement) * SnappingIncrement);
                            if (height > SnappingThresholdHeight)
                                bounds.top = bounds.bottom - ((int)((double)height / (double)SnappingIncrement) * SnappingIncrement);
                            break;

                    }
                    Marshal.StructureToPtr(bounds, lParam, false);
                    break;
            }

            return IntPtr.Zero;
        }
    }
}

This uses increments of 100 to really illustrate the "snapping" effect. In addition, you can adjust the snapping thresholds, which ensure the snapping only takes effect when the size is above a given width/height.

like image 55
CodeNaked Avatar answered Dec 19 '22 05:12

CodeNaked


The old Win32 Listbox had a setting to prevent that. Note that that was solving the problem from the other end.

But take a look at a few established TreeViews first. Like Visual Studio, Tools Options.

I don't think you should be modifying the behaviour of std UI controls this way. Users will only be frustrated if your TV acts 'differently'. They won't call it 'better'.

like image 27
Henk Holterman Avatar answered Dec 19 '22 04:12

Henk Holterman