Winforms - WM_NCHITEST message for click on contro

2019-02-20 00:39发布

问题:

I have a simple windows form with no border and several label controls (nothing that needs to be clicked). I needed to be able to allow the user to move the form by clicking anywhere on it, so I found this question, and used the following code found there.

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

This works well...to a point. If I click anywhere on the form itself (the background), WM_NCHITTEST is HTCLIENT, so I can move my form as expected. However, if I click on a label control itself, the message is something different, and I can't tell what it is.

I found this article about the various possible values for WM_NCHITTEST but none of them seem to be what I need.

I realize I could disable all my label controls and that would allow me to click "on" them as if it was the form itself, but I'm wondering if there's a better/different way to do this.

Thanks for the help!

回答1:

You are overriding the WndProc for the form, but when the cursor is over a label the WM_NCHITTEST message is sent to the label.

You could create your own label control derived from Label and override its WndProc. This should always return HTTRANSPARENT in response to WM_NCHITTEST. Something like:

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

Also note that there's a small bug in your WndProc. If the message is WM_NCHITTEST but the region isn't HTCLIENT then you call the base class twice.