是否有 built-in 快捷键用于选择当前活动表单的所有者?
Is there a built-in shortcut key for selecting the owner of the currently active form?
我有一个主窗体和两个 child 无模式窗体,例如所有表格都可以同时激活:
class MainForm : Form
{
Form child1;
Form child2;
public MainForm()
{
Text = "MainForm";
child1 = new Form { Text = "Child1" };
child2 = new Form { Text = "Child2" };
child1.Show(this);
child2.Show(this);
}
}
我想允许用户 Alt+Tab
进入所有这些,但令人惊讶的是,我发现如果任何 child 表单处于活动状态,则所有者表单不能 select从 Alt+Tab
菜单编辑。
所有三种形式都出现在列表中,但显然当您 select 所有者 window 并且有一个活动的 child 时,child 得到 selected 而不是所有者。在任务栏中 selecting 表单时也会发生同样的事情。
我错过了什么吗?我开始考虑显式配置快捷键以允许从无模式 child 表单导航到所有者 window,但在这样做之前我想确认是否已经有一些 built-in 键盘快捷键到这样做,因为我不想破坏用户的期望。
令人惊讶的是,我找不到任何提及此行为的问题,我也觉得这很奇怪。
编辑后的答案:
我不知道为什么,但就是无法释怀。看来应该有一个简单的解决办法。
@glopes 根据您的评论,我相信这就是您正在寻找的内容。
此代码将在子 window 失去焦点之前将焦点设置回父 window。这类似于单击 window,并允许您按 Alt-Tab 键切换到任何您想要的 window。
public class MainForm : Form
{
Form child1;
Form child2;
public MainForm()
{
Text = "MainForm";
child1 = new ChildForm { Text = "Child1", ParentPtr = Handle };
child2 = new ChildForm { Text = "Child2", ParentPtr = Handle };
child1.Show(this);
child2.Show(this);
}
}
public class ChildForm : Form
{
[DllImport("user32.dll")]
public static extern bool SetFocus(IntPtr hWnd);
private const int WM_KILLFOCUS = 0x0008;
public IntPtr ParentPtr { get; set; }
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_KILLFOCUS) SetFocus(ParentPtr);
base.WndProc(ref m);
}
}
设置表单的所有者,导致此表单作为 non-modal Window.
位于其所有者之上
如果 owned 表单的 ShowInTaskbar
属性 设置为 true
,标准的 ALT+TAB
或 WIN+TAB
组合键用于迭代系统中打开的 Windows,将下一个拥有的表单而不是所有者带到前面(激活)。
child Form被激活,取决于Form在Taskbar中的当前位置。
如果 children 的 ShowInTaskbar
属性 被设置为 false
,所有者表格将被激活。
请注意,如果 child 表单可以最小化,则可以观察到一些尴尬的行为:Alt 或 Control-tabbing,导致 child 表单以不愉快的方式出现和消失。
无论如何,CONTROL+F6
键的标准组合可用于将焦点移动到打开的 child 表单(以及所有者表单,在这种布局中),也将它们带到如有必要(如果表单最小化)放在前面。
在这里,重写 ProcessCmdKey,因此无论 child 控件捕获了光标,组合键都会被 截获 。
此处的代码激活一个表单,同时按下 CONTROL+F6
和 CONTROL+SHIFT+F6
,将焦点移动到每个打开的 child 表单和所有者。它也适用于 child 表单被最小化(或全部)。
在所有者表格中:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool isControlF6 = keyData == (Keys.Control | Keys.F6);
bool isCtrlShiftF6 = keyData == (Keys.Control | Keys.Shift | Keys.F6);
if (isControlF6 || isCtrlShiftF6)
{
Form frm = isCtrlShiftF6
? Application.OpenForms.OfType<Form>().LastOrDefault(f => f.Owner == this)
: Application.OpenForms.OfType<Form>().FirstOrDefault(f => f.Owner == this);
if (frm is null) return true;
frm.WindowState = FormWindowState.Normal;
frm.Focus();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
在 child 表格中:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool isControlF6 = keyData == (Keys.Control | Keys.F6);
bool isCtrlShiftF6 = keyData == (Keys.Control | Keys.Shift | Keys.F6);
if (isControlF6 || isCtrlShiftF6) {
int frmNext = 0;
var formsList = Application.OpenForms.OfType<Form>()
.Where(f => (f.Owner == this.Owner) || (f == this.Owner)).ToList();
for (int i = 0; i < formsList.Count; i++) {
if (formsList[i] == this) {
if (isCtrlShiftF6) { frmNext = i == 0 ? formsList.Count - 1 : i - 1; }
if (isControlF6) { frmNext = i == formsList.Count - 1 ? 0 : i + 1; }
formsList[frmNext].WindowState = FormWindowState.Normal;
formsList[frmNext].Focus();
return true;
}
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
我有一个主窗体和两个 child 无模式窗体,例如所有表格都可以同时激活:
class MainForm : Form
{
Form child1;
Form child2;
public MainForm()
{
Text = "MainForm";
child1 = new Form { Text = "Child1" };
child2 = new Form { Text = "Child2" };
child1.Show(this);
child2.Show(this);
}
}
我想允许用户 Alt+Tab
进入所有这些,但令人惊讶的是,我发现如果任何 child 表单处于活动状态,则所有者表单不能 select从 Alt+Tab
菜单编辑。
所有三种形式都出现在列表中,但显然当您 select 所有者 window 并且有一个活动的 child 时,child 得到 selected 而不是所有者。在任务栏中 selecting 表单时也会发生同样的事情。
我错过了什么吗?我开始考虑显式配置快捷键以允许从无模式 child 表单导航到所有者 window,但在这样做之前我想确认是否已经有一些 built-in 键盘快捷键到这样做,因为我不想破坏用户的期望。
令人惊讶的是,我找不到任何提及此行为的问题,我也觉得这很奇怪。
编辑后的答案:
我不知道为什么,但就是无法释怀。看来应该有一个简单的解决办法。
@glopes 根据您的评论,我相信这就是您正在寻找的内容。
此代码将在子 window 失去焦点之前将焦点设置回父 window。这类似于单击 window,并允许您按 Alt-Tab 键切换到任何您想要的 window。
public class MainForm : Form
{
Form child1;
Form child2;
public MainForm()
{
Text = "MainForm";
child1 = new ChildForm { Text = "Child1", ParentPtr = Handle };
child2 = new ChildForm { Text = "Child2", ParentPtr = Handle };
child1.Show(this);
child2.Show(this);
}
}
public class ChildForm : Form
{
[DllImport("user32.dll")]
public static extern bool SetFocus(IntPtr hWnd);
private const int WM_KILLFOCUS = 0x0008;
public IntPtr ParentPtr { get; set; }
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_KILLFOCUS) SetFocus(ParentPtr);
base.WndProc(ref m);
}
}
设置表单的所有者,导致此表单作为 non-modal Window.
位于其所有者之上
如果 owned 表单的 ShowInTaskbar
属性 设置为 true
,标准的 ALT+TAB
或 WIN+TAB
组合键用于迭代系统中打开的 Windows,将下一个拥有的表单而不是所有者带到前面(激活)。
child Form被激活,取决于Form在Taskbar中的当前位置。
如果 children 的 ShowInTaskbar
属性 被设置为 false
,所有者表格将被激活。
请注意,如果 child 表单可以最小化,则可以观察到一些尴尬的行为:Alt 或 Control-tabbing,导致 child 表单以不愉快的方式出现和消失。
无论如何,CONTROL+F6
键的标准组合可用于将焦点移动到打开的 child 表单(以及所有者表单,在这种布局中),也将它们带到如有必要(如果表单最小化)放在前面。
在这里,重写 ProcessCmdKey,因此无论 child 控件捕获了光标,组合键都会被 截获 。
此处的代码激活一个表单,同时按下 CONTROL+F6
和 CONTROL+SHIFT+F6
,将焦点移动到每个打开的 child 表单和所有者。它也适用于 child 表单被最小化(或全部)。
在所有者表格中:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool isControlF6 = keyData == (Keys.Control | Keys.F6);
bool isCtrlShiftF6 = keyData == (Keys.Control | Keys.Shift | Keys.F6);
if (isControlF6 || isCtrlShiftF6)
{
Form frm = isCtrlShiftF6
? Application.OpenForms.OfType<Form>().LastOrDefault(f => f.Owner == this)
: Application.OpenForms.OfType<Form>().FirstOrDefault(f => f.Owner == this);
if (frm is null) return true;
frm.WindowState = FormWindowState.Normal;
frm.Focus();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
在 child 表格中:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool isControlF6 = keyData == (Keys.Control | Keys.F6);
bool isCtrlShiftF6 = keyData == (Keys.Control | Keys.Shift | Keys.F6);
if (isControlF6 || isCtrlShiftF6) {
int frmNext = 0;
var formsList = Application.OpenForms.OfType<Form>()
.Where(f => (f.Owner == this.Owner) || (f == this.Owner)).ToList();
for (int i = 0; i < formsList.Count; i++) {
if (formsList[i] == this) {
if (isCtrlShiftF6) { frmNext = i == 0 ? formsList.Count - 1 : i - 1; }
if (isControlF6) { frmNext = i == formsList.Count - 1 ? 0 : i + 1; }
formsList[frmNext].WindowState = FormWindowState.Normal;
formsList[frmNext].Focus();
return true;
}
}
}
return base.ProcessCmdKey(ref msg, keyData);
}