Restrict tab order to a single user control - c#

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

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

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

From another question, add this to your UserControl xaml.
KeyboardNavigation.TabNavigation="Cycle"
Restrict tab order to a single user control (WPF)

Related

Make the user's second Tab press act like Ctrl + Tab in WebBrowser Control

I'm trying to make an app where when the user presses Tab two times in a row, the second Tab should act like a Ctrl + Tab instead.
I'm using a toggle = !toggle to detect the second time user presses Tab. Do you know how can I do this without using the KeyDown event (webbrowser control doesn't have those type of events) but using PreviewKeyDown or something similar?
It's expected behavior:
First time user presses Tab, the input should be detected and go through the WebBrowser control (normal behavior)
Second time user presses Tab should be handled and transformed into Ctrl + Tab.
In the below example, I used KeyDown event of WebBrowser.Document.Body. And checked for Tab key and cached the 2nd time the user press it and changed it to a Ctrl+Tab:
int i = 0;
void Body_KeyDown(object sender, HtmlElementEventArgs e)
{
if (e.KeyPressedCode == (int)Keys.Tab && !e.CtrlKeyPressed)
{
if (i == 1)
{
e.ReturnValue = false;
SendKeys.Send("^({TAB})");
this.Text += "[C+T]"; /*Just to be obvious in title-bar for test*/
}
else
{
this.Text += "[T]"; /*Just to be obvious in title-bar for test*/
}
i++;
}
}
To test the solution, make sure you are attached event handlers correctly and after the document load completed, press Tab more than 2 times and look at title bar of form.
The expected result of code is:
First Tab press, acts normally.
Second Tab press will be changed to Ctrl+Tab
Third and so on acts normally
Ctrl+Tab acts normally
Note:
You will see [T][C+T][T][T][T]... in title bar. If you want to see [T][C+T][T][C+T][T][C+T]... just change the criretia to if (i % 2 == 1).

How do I make a text box in a form not visible until after I click compute in C#?

So in the beginning, the user has to input data but in the form. It has textboxes and labels where the answers to the calculations go. I have it so that when it clicks, it computes certain labels and textboxes show up and when the user clicks reset they disappear using:
txtTaxesPaid.Visible = true;
txtTaxesPaid.Visible = false;
My problem is that in the beginning the ones that are not visible. When I click reset they show up. How do I make them not visible in the very beginning?
You can set Textboxes Visible property from Properties window in the designer.Or you can do it in Form Load event programatically:
private void Form1_Load(object sender, EventArgs e)
{
txtTaxesPaid.Visible = false;
}
If you don't see Form Load method just double click your Form in the designer and you will see, or find Load event from Properties > Events window.
Option 1: (shortest and most straight forward)
In VS designer of your form - locate those controls and set the visible property to false.
Option 2:
In your form_load event you can set the initial state of your controls.
Option 3:
You can force to invoke the method of the button which already contain the reset commands from your form_load event.
Option 4: (I think is the preferable choice)
- Create a method for reset..
- call the method from form_load or from your "reset" button or anywhere else you want.
private void ResetControls()
{
txtMyControl.Visible=false;
//here comes more logic for what to do upon reset.
}
private void form_load(...
{
ResetControls();
}
private void btnReset_Click(...
{
ResetControls();
}

Set panel visiblity on Escape key press

Lets say I have a windows form and it has two panels. Main panel and popup panel.When specific button click main panel will disable and popup panel will be visible.
My question is when user press escape key i want to set visibility of popup panel to false and enable main panel.
bool bPanelFocus;
private void cancelButon_Click(object sender, EventArgs e)
{
if (popuppanel.Visible == true && bPanelFocus)
{
popuppanel.Visible = false;
mainpanel.Visible = true;
return;
}
//your code for the cancel button
}
Since you have a cancel button on the form, it will trigger the click event on that button when you press the Esc button. On your cancel button's click event, add a validation to check if the pop up panel is visible, also you might need a flag to check if the user has focus on the panel otherwise proceed with the cancel button's procedures.

Detect in Control.GotFocus whether user navigates forward or backward?

Having the following WinForms dialog form, I am handling the GotFocus event of MyControl:
MyControl derives from the DevExpress XtraUserControl which in turn derives from the Microsoft WinForms standard UserControl.
What I want to achieve is that when MyControl gets the focus when the user navigates with the Tab and MyControl gets the focus, that the focus is forwarded to the child controls.
I do this successfully with the following code:
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
// Forward.
foreach (Control control in Controls)
{
if (control.TabStop)
{
control.Select();
break;
}
}
}
I.e. if Button 1 is focused and the user presses the Tab key, the focus is set to Button 2.
What I'm not able to solve is if the user navigates backward. I.e. if Button 4 is focused and the user presses the Shift+Tab keys, the focus should be set to Button 3.
My two questions are:
Is there a way to detect the navigation order of the user inside the GotFocus event?
Am I doing it the right way at all? Maybe there is a built-in function/flag I can set to MyControl to automatically forward the focus to its child controls?
So many possibilities:
use the OnLostFocus event to store the current control and calculate whether TAB or SHIFT TAB was pressed
override ProcessKeyPreview to calc the action to be performed in OnGotFocus (SO answer)
override ProcessCmdKey as in this answer

WinForm - TabStop Not Working

I have a WinForm with 3 group boxes, one with combo boxes, and two with radio buttons. I set all of them and their children controls to "TabStop = false", but when I cycle with TAB, the currently selected radio button in each of the last two group boxes gets focused.
If there's no way to change this behavior, what would be a good event to catch and move the focus away? I can't find an "OnFocus" event.
The solution is to set one method (code below) to handle the "Enter" event of every radio button in the form (if that's what you wish).
Actually, I only did it for the radio buttons of the first group box and it worked, the second group box's radio buttons don't get focus, even though their "Enter" events are not handled. This is not the behavior you would have expected.
private void radiobuttonXGroup1_Enter(object sender, EventArgs e)
{
SomeOtherControl.Focus();
}
In the *.Designer.cs file you edit every Enter event (for each radio button) to point to one event handler (the above method).
this.radiobutton1Group1.Enter += new System.EventHandler(this.radiobuttonXGroup1_Enter);
this.radiobutton2Group1.Enter += new System.EventHandler(this.radiobuttonXGroup1_Enter);
this.radiobutton3Group1.Enter += new System.EventHandler(this.radiobuttonXGroup1_Enter);
Setting the TabStop to False on a RadioButton to prevent tabbing to the control works until you actully select the radio button without any additional overrides like suggested by #msergeant.
EDIT
The following code prevents the code from getting a tab key event:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
radioButton1.TabStop = false;
}
Radio buttons behave differently with respect to Tab from other controls in that they work in sets or groups based on setting the tab index or placing then radio buttons in a group box.
The MSDN documentation for RadioButton.TabStop states "This API supports the .NET Framework infrastructure and is not intended to be used directly from your code". Which basically means, "This isn't going to work how you expect it to".
With that said, the Enter event will fire when the button receives the focus. You can try to use that to move focus to another control.

Categories