Есть ли встроенная комбинация клавиш для выбора владельца текущей активной формы?
У меня есть основная форма с двумя дочерними немодальными формами, например, все формы могут быть активными одновременно:
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
во всех них, но удивительно, я обнаружил, что если какая-либо из дочерних форм активна, форму владельца нельзя выбрать из Alt+Tab
меню.
Все три формы отображаются в списке, но, очевидно, когда вы выбираете окно владельца и появляется активный дочерний элемент, выбирается дочерний элемент, а не владелец. То же самое происходит при выборе форм на панели задач.
Я что-то пропустил? Я начал думать о явной настройке сочетаний клавиш, чтобы разрешить переход от немодальной дочерней формы к окну владельца, но перед этим я хотел убедиться, что для этого уже есть встроенное сочетание клавиш, поскольку я не хочу сломать ожидания пользователей.
Удивительно, но я не смог найти ни одного вопроса, упоминающего это поведение, что я также нашел довольно странным.
2 ответа
Установка владельца формы приводит к тому, что эта форма остается поверх своего владельца как немодальное окно.
Если форма принадлежит ShowInTaskbar
свойство установлено в true
, стандарт ALT+TAB
или же WIN+TAB
комбинация клавиш, используемая для перебора открытой Windows в Системе, выводит на передний план (активирует) следующую принадлежащую Форму вместо Владельца.
Какая дочерняя форма активирована, зависит от текущей позиции формы на панели задач.
Если ShowInTaskbar
свойство детей вместо этого установлено в false
, Форма владельца активирована.
Чтобы отметить, что если дочерняя форма может быть свернута, можно наблюдать некоторое неловкое поведение: Alt или Tab-tabbing, приводят к тому, что дочерние формы появляются и исчезают неприятным образом.
Во всяком случае, стандартная комбинация CONTROL+F6
ключи можно использовать для перемещения фокуса на открытые дочерние формы (и форму владельца, в этом типе макета), а также, если необходимо, вывести их на передний план (если форма свернута).
Здесь переопределяем ProcessCmdKey, поэтому комбинация клавиш перехватывается независимо от того, какой дочерний элемент управления захватил курсор.
Код здесь активирует форму, нажимая оба CONTROL+F6
а также CONTROL+SHIFT+F6
, перемещая Фокус к каждой из открытых дочерних форм и Владельца. Это также работает, когда дочерняя форма свернута (или все они).
В форме владельца:
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);
}
В детской форме:
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);
}
Отредактированный ответ:
Я не знаю почему, но я просто не мог отпустить это. Казалось, должно быть простое решение.
@ Glopes Я думаю, что это то, что вы ищете, основываясь на вашем комментарии.
Этот код установит фокус обратно на родительское окно непосредственно перед тем, как дочернее окно потеряет фокус. Это действует аналогично нажатию на окно и позволяет вам Alt-Tab для любого окна, которое вы хотите.
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);
}
}