'How do I restore focus to previously focused control of the TabPage when switching between tabs
I have a TabControl and I'm adding Tabpages to it programmatically. Each TabPage loads a UserControl in it, and each user control contains a few controls. For example:
TabPage1
UserControl1
TextBox1, TextBox2, TextBox3
TabPage2
UserControl2
TextBox4, TextBox5, TextBox6
Now I want that whenever the user changes the tab, the previously-focused control of that tab get focus again when the tab is selected again.
Example:
- Let's say the focus is on TabPage1 → UserControl1 → TextBox2
- Then I click on TagPage 2 → UserControl2 → TextBox4
- Then I again click on TabPage1 and I want TextBox2 get the focus.
What shall I do?
Solution 1:[1]
Possible solution:
Override UpdateDefaultButton() in your Form; this method is called each time a Control becomes the ActiveControl
.
Of course, if you have UserControls inside TabPages, the ActiveControl is the UserControl, but you need its child Control that is currently focused.
In the sample code, I'm using the GetFocus() function to get the handle of the focused Control, then use Control.FromHandle() to get the Control instance with that handle and, if it's not null
, store this information in a Dictionary, along with the current TabPage.
When the TabControl's Selected event is raised, check whether the Dictionary has stored the new current TabPage and, if a Control is associated with that TabPage, move the focus on it.
(I'm using BeginInvoke()
because we're changing the ActiveControl in the Selected
handler, which would in turn cause a call to UpdateDefaultButton()
)
- Note that I'm not verifying here whether the Focused Control is child of a different container than the TabPage: if you have nested Containers in your TabPages, you need a recursive method that checks whether one of the ancestors is a TabPage.
Private tabPagesActiveControl As New Dictionary(Of Integer, Control)
Protected Overrides Sub UpdateDefaultButton()
MyBase.UpdateDefaultButton()
If ActiveControl Is Nothing Then Return
If TypeOf ActiveControl.Parent Is TabPage Then
Dim tp = DirectCast(ActiveControl.Parent, TabPage)
Dim tabPageIdx = DirectCast(tp.Parent, TabControl).SelectedIndex
Dim ctl = FromHandle(GetFocus())
If ctl IsNot Nothing Then
If tabPagesActiveControl.Count > 0 AndAlso tabPagesActiveControl.ContainsKey(tabPageIdx) Then
tabPagesActiveControl(tabPageIdx) = ctl
Else
tabPagesActiveControl.Add(tabPageIdx, ctl)
End If
End If
End If
End Sub
Private Sub TabControl1_Selected(sender As Object, e As TabControlEventArgs) Handles TabControl1.Selected
Dim ctl As Control = Nothing
If tabPagesActiveControl.TryGetValue(e.TabPageIndex, ctl) Then
BeginInvoke(New Action(Sub() ctl.Focus()))
End If
End Sub
Win32 Function declaration:
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Friend Shared Function GetFocus() As IntPtr
End Function
C# Version:
private Dictionary<int, Control> tabPagesActiveControl = new Dictionary<int, Control>();
protected override void UpdateDefaultButton()
{
base.UpdateDefaultButton();
if (ActiveControl is null) return;
if (ActiveControl.Parent is TabPage tp) {
var tabPageIdx = (tp.Parent as TabControl).SelectedIndex;
var ctl = FromHandle(GetFocus());
if (ctl != null) {
if (tabPagesActiveControl.Count > 0 && tabPagesActiveControl.ContainsKey(tabPageIdx)) {
tabPagesActiveControl[tabPageIdx] = ctl;
}
else {
tabPagesActiveControl.Add(tabPageIdx, ctl);
}
}
}
}
private void tabControl1_Selected(object sender, TabControlEventArgs e)
{
if (tabPagesActiveControl.TryGetValue(e.TabPageIndex, out Control ctl)) {
BeginInvoke(new Action(() => ctl.Focus()));
}
}
Win32 Function declaration:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr GetFocus();
This is how it works:
Note: TabPage2
and TabPage3
contain the instance of a UserControl with 2 TextBoxes and a ListBox. TabPage1
contains a TextBox and a NumericUpDown.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |