C#表单控件移动

3

有没有办法控制表单的移动位置?

如果我移动一个表单,它只能在垂直轴上移动,当我尝试水平移动时,什么也不会发生。

我不想要像locationchanged或move事件这样有缺陷的实现方式,并将其弹回到行内。我知道可以使用类似于WndProc覆盖的方法,但是经过一段时间的搜索,我找不到任何东西。请帮帮我。

3个回答

3

例如:

using System.Runtime.InteropServices;

protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x216)  // WM_MOVING = 0x216
    {
        Rectangle rect = 
           (Rectangle) Marshal.PtrToStructure(m.LParam, typeof (Rectangle));
        if (rect.Left < 100)
        {
            // compensates for right side drift
            rect.Width = rect.Width + (100 - rect.Left);
            // force left side to 100
            rect.X = 100;
            Marshal.StructureToPtr(rect, m.LParam, true);
        }
    }
    base.WndProc(ref m);
}

以上代码设置了最小左侧位置为100。

无需像driis那样重新创建RECT结构,.NET的原生Rectangle可以正常工作。但是,您必须通过X属性设置位置,因为Left是只读属性。


你还需要处理其他消息,因为在窗口首次创建时不会调用WM_MOVING。要么在创建时显式设置窗口位置,要么确保它在创建时处于所需的限制范围内。 - Erik Funkenbusch

2
您可能希望重写WndProc并处理WM_MOVING消息。根据MSDN的说法,WM_MOVING消息是发送给正在移动的窗口的。通过处理此消息,应用程序可以监视拖动矩形的位置,并在需要时更改其位置。这将是一种实现的方法,但您显然需要根据自己的需求进行调整。
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace VerticalMovingForm
{
    public partial class Form1 : Form
    {
        private const int WM_MOVING = 0x0216;
        private readonly int positionX;
        private readonly int positionR;

        public Form1()
        {
            Left = 400;
            Width = 500;                            
            positionX = Left;
            positionR = Left + Width;
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_MOVING)
            {
                var r = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
                r.Left = positionX;
                r.Right = positionR;
                Marshal.StructureToPtr(r, m.LParam, false);
            }
            base.WndProc(ref m);                
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
    }
}

1

VB.NET 版本:

Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    If m.Msg = &H216 Then
        ' WM_MOVING = 0x216
        Dim rect As Rectangle = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(Rectangle)), Rectangle)
        If rect.Left < 100 Then
            ' compensates for right side drift
            rect.Width = rect.Width + (100 - rect.Left)
            ' force left side to 100
            rect.X = 100
            Marshal.StructureToPtr(rect, m.LParam, True)
        End If
    End If
    MyBase.WndProc(m)
End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接