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

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

Related

WPF Lost-Focus issue in same control

I have a small problem with focusing in .net/wpf. I have written a custom user control which contains a TextBox and a SearchButton. The user-control has a lost focus event, which validate the content of the textbox if the focus is leaving. But now I have the problem, if I click on my search button, the lost focus event of the user control gets fired, even if I click on the button in the custom user control. (The button additionally has the option TabStop="False":
The problem is, that I don't want to fire the event if I click on the button.
Set
Focusable="False"
of your search button and the TextBox will not lose the focus because the button doesn't get the focus.
You can Do this Check in Event like this
protected void LostFocusEvent(object sender, RoutedEventArgs e)
{
if(textBox.Text.Length>0)
{
// if there is any character in TextBox
return;
}
// your validation Code goes here
}

c# Prevent dragging box over another

I am using visual studio. In my program I have the option for a user to activate certain widgets that they want to have. Each widget is a UserControl, so when they click to show a widget, it is activating the corresponding user control. Once they activate the control, they can drag the boxes wherever they wish so that they can customize how their screen looks. However, whenever you drag one widget over another, it just stacks them on top of each other, and this is not what I want. If I am dragging a box and it touches another one, I want it to stop and not be able to overlap it. How can I do this? I suspect it has something to do with the "DragOver" event, but not for sure.
The DragOver event will be raised on these case :
[+] If the user moves out of a window, the DragLeave event is raised.
[+] If the mouse enters another control, the DragEnter for that control is raised.
[+]If the mouse moves but stays within the same control, the DragOver event is raised.
If this is the event that you want, so try to terminate the widget (User Control) on UserControl_DragOver.
You can terminate your UserControl like this :
private void Btn_Cancel_Click(object sender, EventArgs e)
{
this.Parent.Controls.Remove(this);
}
(If you mean sth else, tell in comment)

C# focus in forms and arrow keys

I want to do a map editor for a game. Its a program that will have Windows Forms UI (like propertyGrid to edit object's properties) but it will also have a panel on which map will be drawn.
What i want:
When focus is on the panel with the map, i'd like to use keyboard to move map around (arrow keys), add objects (number keys) etc. When focus isnt on this panel, i'd like the buttons to work as normal in windows forms - allow to tab between controls etc.
My form looks like this:
It has a ToolStripControl that has a menuStrip (for main menu) and a statusStrip (for status bar). In the middle of the form (or toolstripcontrol), SplitControl is docked (dock=fill) that has two panels. Panel 1 has the PanelMap - a Panel that displays the map, Panel 2 has all other stuff like propertygrid, tabcontrols, buttons etc.
I have KeyPreview of form set to true and process keyboard events in form's keydown event handler.
Now, what happens is if i assign focus to PanelMap, next time i press an arrow key, NO KeyDown event fires. Not a single one! Even form which is supposed to process all events because it has "KeyPreview" doesnt get its even to fire. When i press an arrow, PanelMap loses focus towards the SplitControl.
Okay, i thought, maybe PanelMap is not supposed to ever have focus, lets give focus to SplitControl (if i press arrow key while it has focus, i can handle it so it doesnt go further). But then, if anything like a textbox that is inside something that is inside SplitControl has focus, then SplitControl CANNOT get focus. .Focus() will do nothing - focus remains in the whichever control that had it!
Why does it act so strange? Why doesnt Form's KeyDown fire when panel has focus and arrow key is pressed? Why doesnt SplitControl get focused when i call .Focus() even though CanFocus=true?
And ultimately, how do i achieve what i want? Is there a way to do it?
I think you're running into the widgets taking the keystrokes before your events get to them for navigation. I had this issue, and did this:
private void RemoveCursorNavigation(Control.ControlCollection controls)
{
foreach(Control ctrl in controls)
{
ctrl.PreviewKeyDown += new PreviewKeyDownEventHandler(MainWin_PreviewKeyDown);
RemoveCursorNavigation(ctrl.Controls);
}
}
I call this function in the main form's Load handler, like this:
RemoveCursorNavigation(this.Controls);
In your PreviewKeyDown handler, you need to do this:
public void MainWin_PreviewKeyDown(Object sender, PreviewKeyDownEventArgs e)
{
switch(e.KeyCode)
{
case Keys.Up:
case Keys.Down:
case Keys.Left:
case Keys.Right:
e.IsInputKey = true;
break;
default:
break;
}
}
The e.IsInputKey = true; tells the outside that you've used this event, and don't want it going anywhere else.
Now you get to see the keystrokes before they go to the widgets, and you won't get navigation between them from the cursor keys.
I found an answer like this:
I made a textbox that is hidden under a panel (but enabled and visible). This textbox is given focus when i want to "lock" focus on my PanelMap. It has onkeydown even with e.suppress = true so that textbox never gets any keystrokes to affect it.
Crude workaround but works wonders... typical M$ business...

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

How to bypass the enter/leave event in c sharp

I'm having a Picture box in a user control window(Windows custom control library). and some functionality in the Form's Enter event and leave event.
Now my sample application is having two instances of the control. So when i run my sample application the fist control got selected and the enter event is triggered, and when i select the second control the first's leave and second's enter events are getting triggered.
Now, problem is that when i select(click) the second control's picturebox, the events are not triggering, i.e the control form is not getting the event.
So if i click whereever in the control(in the picturebox or in the control) the enter event should be triggered.
How to do this?
A picture box can't get focus. So clicking on it won't take the focus away from the previous control thus not triggering the events.
You need to add a click handler on the picture box in which you manually give focus to the associated focusable control.
private void PictureBox_Click(object sender, EventArgs e)
{
focusableControl.Focus();
}

Categories