如何以增量调整WPF窗口的大小?

时间:2011-04-20 20:28:11

标签: c# .net wpf xaml

是否可以制作Window,以便当用户调整高度时,它会递增和递减10?有点像对齐大小调整。

6 个答案:

答案 0 :(得分:4)

以下是如何完成此操作的示例:

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

这使用100的增量来真正说明“捕捉”效果。此外,您可以调整捕捉阈值,以确保捕捉仅在尺寸高于给定宽度/高度时生效。

答案 1 :(得分:3)

旧的Win32 Listbox有一个设置来防止这种情况。请注意,这是从另一端解决问题。

但首先看几个已建立的TreeViews。与Visual Studio,工具选项一样。

我认为你不应该以这种方式修改std UI控件的行为。如果您的电视节目“不同”,用户只会感到沮丧。他们不会称之为“更好”。

答案 2 :(得分:3)

让窗口变成用户不想要的尺寸可能不是很好......如果它们最大化窗口会发生什么,它不是10的倍数?如果他们拖动窗口的上边缘,你能否将其他窗口边框保持在同一个位置?

我会专注于TreeView:创建一个实现MeasureOverride的容器,并让实现调用base.MeasureOverride,当它获得该结果时,将值向下舍入(总是向下)到10的倍数。窗口内容的其余部分将获得不同的空间,具体取决于窗口的大小,但只需确保您的布局中有一些内容可以拉伸以占用额外的0-9像素。

答案 3 :(得分:1)

好吧,通常你会想要处理调整大小/调整大小事件,然后将大小向上或向下舍入到十的倍数或类似的东西。

然而,在WPF中,你显然不得不使用行为进行黑客攻击。

请参阅this article,因为它描述了访问调整大小事件所需执行的操作。

答案 4 :(得分:1)

您可以将SizeChangedEventHandler添加到SizeChanged事件中。然后在您的委托方法中,手动更改大小。

虽然我认为除非你把它记录在某个地方,否则很难知道它有多大改变。

答案 5 :(得分:0)

好吧,我准备说:“以一种简单的方式,并且不写脏兮兮的代码隐藏?不是我的知识”。

......我会坚持那个xD