C# Winforms-单击控件的WM_NCHITEST消息

C# Winforms-单击控件的WM_NCHITEST消息,c#,.net,winforms,wndproc,C#,.net,Winforms,Wndproc,我有一个简单的windows窗体,没有边框和几个标签控件(无需单击)。我需要允许用户通过点击表单上的任意位置来移动表单,所以我找到了这个问题,并使用了下面的代码 private const int WM_NCHITTEST = 0x84; private const int HTCLIENT = 0x1; private const int HTCAPTION = 0x2; protected override void WndProc(ref Message

我有一个简单的windows窗体,没有边框和几个标签控件(无需单击)。我需要允许用户通过点击表单上的任意位置来移动表单,所以我找到了这个问题,并使用了下面的代码

    private const int WM_NCHITTEST = 0x84;
    private const int HTCLIENT = 0x1;
    private const int HTCAPTION = 0x2;

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg) {
            case WM_NCHITTEST:
                base.WndProc(ref m);

                if ((int)m.Result == HTCLIENT) {
                    m.Result = (IntPtr)HTCAPTION;
                    return;
                } else {
                    return;
                }
                break;
        }
        base.WndProc(ref m);            
    }
在某种程度上,这很有效。如果我单击表单本身的任何位置(背景),
WM\u nchitest
HTCLIENT
,因此我可以按预期移动表单。但是,如果我单击标签控件本身,消息会有所不同,我无法分辨它是什么

我找到了
WM\u NCHITTEST
的各种可能值,但它们似乎都不是我所需要的

我意识到我可以禁用所有标签控件,这样我就可以像单击表单本身一样单击它们,但我想知道是否有更好/不同的方法来做到这一点


谢谢你的帮助

您正在覆盖表单的
WndProc
,但当光标位于标签上时,
WM\n chittest
消息将发送到标签

您可以创建自己的标签控件,该控件派生自
label
,并重写其
WndProc
。这应始终返回
HTTRANSPARENT
,以响应
WM\u nchitest
。比如:

private const int HTTRANSPARENT = -1;

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_NCHITTEST:
            m.Result = (IntPtr)HTTRANSPARENT;
            return;
    }
    base.WndProc(ref m);
}

还要注意,您的
WndProc
中有一个小错误。如果消息是
WM\u NCHITTEST
但区域不是
HTCLIENT
,则调用基类两次。

您将覆盖表单的
WndProc
,但当光标位于标签上时,
WM\u NCHITTEST
消息将发送到标签

您可以创建自己的标签控件,该控件派生自
label
,并重写其
WndProc
。这应始终返回
HTTRANSPARENT
,以响应
WM\u nchitest
。比如:

private const int HTTRANSPARENT = -1;

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_NCHITTEST:
            m.Result = (IntPtr)HTTRANSPARENT;
            return;
    }
    base.WndProc(ref m);
}

还要注意,您的
WndProc
中有一个小错误。如果消息是
WM\u nchitest
但区域不是
HTCLIENT
,那么您可以调用基类两次。

为什么您不能告诉消息是什么(即它是否出错或只是返回了您不期望的内容)?记录您可以期望的值-您是否得到了其他东西?@RobP。好问题!我想我应该进入调试模式,尝试查看单击控件时的消息是什么——但不幸的是,当我将鼠标悬停在窗体上时,断点一直被击中。然后,我必须在visual studio中点击f5才能运行,并将鼠标移回窗体上,等等。我尝试在m.Result上使用debug.writeline,但无论事件实际是什么,它总是打印1而不打印其他内容。windows消息的调试可能非常棘手。Spy++是实现这类功能的必备工具。为什么你不能说出消息是什么(即它是否出错或只是返回了你不期望的东西)?记录您可以期望的值-您是否得到了其他东西?@RobP。好问题!我想我应该进入调试模式,尝试查看单击控件时的消息是什么——但不幸的是,当我将鼠标悬停在窗体上时,断点一直被击中。然后,我必须在visual studio中点击f5才能运行,并将鼠标移回窗体上,等等。我尝试在m.Result上使用debug.writeline,但无论事件实际是什么,它总是打印1而不打印其他内容。windows消息的调试可能非常棘手。Spy++是实现这类功能的必备工具。我已经修复了代码中的错误(或者至少我认为我已经修复了)。我会用自定义标签试试你的想法,然后再给你回复。如何将-1表示为十六进制?我尝试了
0x-1
,但似乎不起作用…(无效数字)我也尝试了
-1
,没有出现错误,但似乎与
WM\u NCHITTEST
不匹配。我不想将结果设置为
HTTRANSPARENT
,不过,我想将其更改为
HTCLIENT
。为了澄清,测试
m.Result
似乎永远不会等于
HTTRANSPARENT
。不要在标签控件WndProc中测试
m.Result
,只需将结果设置为
HTTRANSPARENT
,如上代码所示。然后Windows将消息转发到表单,您将像以前一样返回
HTCAPTION
。如果您返回标签的
HTCAPTION
,Windows将忽略它。啊,我最初误解了您。刚刚测试过,效果很好-非常感谢!我已经修复了代码中的错误(或者至少我认为我已经修复了)。我会用自定义标签试试你的想法,然后再给你回复。如何将-1表示为十六进制?我尝试了
0x-1
,但似乎不起作用…(无效数字)我也尝试了
-1
,没有出现错误,但似乎与
WM\u NCHITTEST
不匹配。我不想将结果设置为
HTTRANSPARENT
,不过,我想将其更改为
HTCLIENT
。为了澄清,测试
m.Result
似乎永远不会等于
HTTRANSPARENT
。不要在标签控件WndProc中测试
m.Result
,只需将结果设置为
HTTRANSPARENT
,如上代码所示。然后Windows将消息转发到表单,您将像以前一样返回
HTCAPTION
。如果您返回标签的
HTCAPTION
,Windows将忽略它。啊,我最初误解了您。刚刚测试过,效果很好-非常感谢!