在选项卡之间切换时,如何将焦点恢复到之前聚焦的 TabPage 控件
How do I restore focus to previously focused control of the TabPage when switching between tabs
我有一个 TabControl,我正在以编程方式向其添加 Tabpages。
每个TabPage在里面加载一个UserControl,每个用户控件又包含几个控件。例如:
TabPage1
UserControl1
TextBox1, TextBox2, TextBox3
TabPage2
UserControl2
TextBox4, TextBox5, TextBox6
现在我希望每当用户更改选项卡时,当再次选择该选项卡时,该选项卡先前获得焦点的控件再次获得焦点。
示例:
- 假设焦点在 TabPage1 → UserControl1 → TextBox2
- 然后我点击 TagPage 2 → UserControl2 → TextBox4
- 然后我再次单击 TabPage1,我希望 TextBox2 获得焦点。
我该怎么办?
可能的解决方案:
覆盖您表单中的 UpdateDefaultButton();每次控件变为 ActiveControl
.
时都会调用此方法
当然,如果你在TabPages里面有UserControl,ActiveControl就是UserControl,但是你需要它的子Control是当前获得焦点的。
在示例代码中,我使用 GetFocus() function to get the handle of the focused Control, then use Control.FromHandle() 获取具有该句柄的 Control 实例,如果不是 null
,则将此信息与当前的句柄一起存储在字典中TabPage.
当 TabControl 的 Selected 事件被引发时,检查 Dictionary 是否存储了新的当前 TabPage,如果控件与该 TabPage 相关联,则将焦点移到它上面。
(我正在使用 BeginInvoke()
,因为我们正在更改 Selected
处理程序中的 ActiveControl,这将导致调用 UpdateDefaultButton()
)
- 请注意,我在这里没有验证 Focused Control 是否是与 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#版本:
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();
这是它的工作原理:
注意:TabPage2
和 TabPage3
包含带有 2 个文本框和一个列表框的 UserControl 实例。 TabPage1
包含一个 TextBox 和一个 NumericUpDown。
我有一个 TabControl,我正在以编程方式向其添加 Tabpages。 每个TabPage在里面加载一个UserControl,每个用户控件又包含几个控件。例如:
TabPage1
UserControl1
TextBox1, TextBox2, TextBox3
TabPage2
UserControl2
TextBox4, TextBox5, TextBox6
现在我希望每当用户更改选项卡时,当再次选择该选项卡时,该选项卡先前获得焦点的控件再次获得焦点。
示例:
- 假设焦点在 TabPage1 → UserControl1 → TextBox2
- 然后我点击 TagPage 2 → UserControl2 → TextBox4
- 然后我再次单击 TabPage1,我希望 TextBox2 获得焦点。
我该怎么办?
可能的解决方案:
覆盖您表单中的 UpdateDefaultButton();每次控件变为 ActiveControl
.
时都会调用此方法
当然,如果你在TabPages里面有UserControl,ActiveControl就是UserControl,但是你需要它的子Control是当前获得焦点的。
在示例代码中,我使用 GetFocus() function to get the handle of the focused Control, then use Control.FromHandle() 获取具有该句柄的 Control 实例,如果不是 null
,则将此信息与当前的句柄一起存储在字典中TabPage.
当 TabControl 的 Selected 事件被引发时,检查 Dictionary 是否存储了新的当前 TabPage,如果控件与该 TabPage 相关联,则将焦点移到它上面。
(我正在使用 BeginInvoke()
,因为我们正在更改 Selected
处理程序中的 ActiveControl,这将导致调用 UpdateDefaultButton()
)
- 请注意,我在这里没有验证 Focused Control 是否是与 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#版本:
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();
这是它的工作原理:
注意:TabPage2
和 TabPage3
包含带有 2 个文本框和一个列表框的 UserControl 实例。 TabPage1
包含一个 TextBox 和一个 NumericUpDown。