可能的解决方案:
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.
在示例代码中,我使用GetFocus()函数获取聚焦控件的句柄,然后使用Control.FromHandle()获取带有该句柄的控件实例,如果不是null
,则将该信息与当前选项卡页一起存储在字典中.
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()
)
- 注意,这里我并不是在验证聚焦控件是否是TabPage之外的其他容器的子容器:如果TabPage中有嵌套的容器,则需要一个递归方法来判断祖先之一是否是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函数声明:
<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函数声明:
[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.