Pergunta

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
Foi útil?

Solução 3

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

Outras dicas

You can override the Controls' KeyDown event and manually move the focus over to the Control that should receive focus.

Aside from that, I agree with Will Hughes that it might break navigation...

I'm assuming you have some button you press that toggles the visibility of your B user control. And if it is visible and has focus then it keeps focus. It loses focus only when you toggle it to hidden. If that's the case, you could try this code in your A form which will keep your focus in the user control unless you hide the user control:

// store when we last clicked the toggle B user control visibility
private Stopwatch _sinceLastMouseClick;

public Form1()
{
    InitializeComponent();
    // instantiate the stopwatch and start it ticking
    _sinceLastMouseClick = new Stopwatch();
    _sinceLastMouseClick.Start();
}

The button that toggles the visibility on your floating B control's click handler:

private void btnToggleBUserControlVisibility_Click(object sender, EventArgs e)
{
    // reset the stopwatch because we just clicked it
    _sinceLastMouseClick.Restart();
    myUserControl1.Visible = !myUserControl1.Visible;
}

In your parent A form, handle the floating user control's Leave event:

private void myUserControl1_Leave(object sender, EventArgs e)
{
    // see if the mouse is over the toggle button
    Point ptMouse = System.Windows.Forms.Control.MousePosition;
    Point ptClient = this.PointToClient(ptMouse);
    // if the mouse is NOT hovering over the toggle button and has NOT just clicked it,
    // then keep the focus in the user control.
    // We use the stopwatch to make sure that not only are we hovering over the button
    // but that we also clicked it, too
    if (btnToggleBUserControlVisibility != this.GetChildAtPoint(ptClient) ||
        _sinceLastMouseClick.ElapsedMilliseconds > 100)
    {
        myUserControl1.Focus();
    }
}

From another question, add this to your UserControl xaml.

KeyboardNavigation.TabNavigation="Cycle"

Restrict tab order to a single user control (WPF)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top