Winforms - 单击控件的 WM_NCHITEST 消息

Man*_*eld 4 .net c# wndproc winforms

我有一个简单的窗口窗体,没有边框和几个标签控件(不需要单击任何内容)。我需要能够允许用户通过单击表单上的任意位置来移动表单,所以我找到了这个问题,并使用了在那里找到的以下代码。

    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);            
    }
Run Code Online (Sandbox Code Playgroud)

在某种程度上,这很有效。如果我单击表单本身(背景)上的任意位置,WM_NCHITTEST则为HTCLIENT,这样我就可以按预期移动表单。但是,如果我单击标签控件本身,则消息会有所不同,并且我无法分辨它是什么。

我发现这篇文章介绍了各种可能的值,WM_NCHITTEST但它们似乎都不是我需要的。

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

谢谢您的帮助!

arx*_*arx 5

您正在覆盖WndProc表单的 ,但是当光标位于标签上时,WM_NCHITTEST消息将发送到标签。

您可以创建自己的标签控件,派生自Label并覆盖其WndProc. 这应该始终返回HTTRANSPARENT以响应WM_NCHITTEST. 就像是:

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);
}
Run Code Online (Sandbox Code Playgroud)

另请注意,您的WndProc. 如果消息是,WM_NCHITTEST但区域不是,HTCLIENT那么您将调用基类两次。