Search code examples
c#.netwinformsuser-controlstab-ordering

Restrict tab order to a single user control


I have a user control that behaves as a floating control, and I would like to restrict the tab order only to my user control when its visible. Basically what I need is to have a control that behaves like a borderless Form. Actually it was a Form, but I needed to preserve the Focus in the MainForm window, so I had to change it to be a UserControl.

So, imagine a Form A (MainForm), and my UserControl B. B is a child control of A. Suppose that Form A has a button and a TextBox, and the control B also has a button and a Textbox. The secuence that currenly occurs is the following

What currently happens (natural tab order behavior):

When only A is visible (B is not visible):

1. The user manually focuses A textbox
2. Press tab key
3. A button is focused

When A is visible and also B is visible: (the natural tab order key is the following):

1. The user manually focuses B textbox
2. Press tab key
3. B button is focused
4. Press tab key
5. A textbox is focused
6. Press tab key
7. A button is focused

What I need (I need to change my user control to preserve the focus):

What I really need is that the B control preserves the tab order inside it, so what I need is with when B control is visible:

1. The user manually focuses B texbox
2. Press tab key
3. B button is focused
4. Press tab key
5. B textbox is focused

Solution

  • Finally I solved the issue including the following code in the parent control:

        private int WM_KEYDOWN = 0x100;
    
        public override bool PreProcessMessage(ref Message msg)
        {
            Keys key = (Keys)msg.WParam.ToInt32();
    
            if (msg.Msg == WM_KEYDOWN && key == Keys.Tab)
            {
                if (itemSearchControl.Visible)
                {
                    bool moveForward = !IsShiftKeyPressed();
                    bool result = itemSearchControl.SelectNextControl(itemSearchControl.ActiveControl, true, true, true, true);
                    return true;
                }
            }
    
            return base.PreProcessMessage(ref msg);
        }