Kevin Vuilleumier
Kevin Vuilleumier

Reputation: 629

Two issues with WS_EX_NOACTIVATE and WinForms

In some of my applications, I use the WS_EX_NOACTIVATE extended window style value (e.g. to create a Virtual Keyboard or for a form hosted in another program). This value prevents the form to get focus.

Here is how I proceed:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams p = base.CreateParams;

        p.ExStyle |= Win32.WS_EX_NOACTIVATE;

        return p;
    }
}

It works well, but I notice two issues with this solution:

  1. Users can not move between controls by pressing "Tab"
  2. When users drag the form, we can not see the displacement (form is not redraw during move)

So, is it possible to fix these issues or, at least, to implement some alternatives? Maybe WS_EX_NOACTIVATE is not the best solution to do that?

Many thanks!

Upvotes: 2

Views: 1275

Answers (1)

Kevin Vuilleumier
Kevin Vuilleumier

Reputation: 629

Here are the the solutions I found for each issue:


Issue #1:

protected override bool ProcessKeyPreview(ref Message m)
{
    if (m.Msg == Win32.WM_KEYDOWN && (Keys)m.WParam == Keys.Tab)
    {
        if (Control.ModifierKeys == Keys.Shift)
        {
            this.SelectNextControl(ActiveControl, false, true, true, true);  // Bring focus to previous control
        }
        else
        {
            this.SelectNextControl(ActiveControl, true, true, true, true);  // Bring focus to next control
        }
    }

    return base.ProcessKeyPreview(ref m);
}

Issue #2: you must intercept the appropriate messages received from system (WM_SIZING and WM_MOVING) and set the position of the form with SetWindowPos() - this will force it to move!

In your Form's class:

public const int WM_SIZING = 0x0214;
public const int WM_MOVING = 0x0216;

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

[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInstertAfter, int x, int y, int cx, int cy, uint flags);

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_SIZING || m.Msg == WM_MOVING)
    {
        RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
        SetWindowPos(this.Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top, 0);
    }
    else
    {
        base.WndProc(ref m);
    }
}

Upvotes: 3

Related Questions