Есть ли встроенная комбинация клавиш для выбора владельца текущей активной формы? - PullRequest
0 голосов
/ 24 февраля 2019

У меня есть основная форма с двумя дочерними немодальными формами, например, все формы могут быть активными одновременно:

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 ]

0 голосов
/ 25 февраля 2019

Установка владельца формы приводит к тому, что эта форма остается поверх своего владельца в качестве немодального окна.
Если принадлежит Форма имеет свойство ShowInTaskbar, установленное на true, стандартная комбинация клавиш ALT+TAB или WIN+TAB, используемая для перебора открытых окон в Системе, выводит на передний план (активирует) следующую принадлежащую Форму вместо Владельца.
Какой дочерний элемент Форма активирована, это зависит от текущей позиции формы на панели задач.

Если вместо свойства ShowInTaskbar дочерних элементов установлено значение false, активируется форма владельца.
Чтобы заметить, что если дочерняя форма может быть свернута, может наблюдаться некоторое неловкое поведение:Alt или Control-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);
}
0 голосов
/ 24 февраля 2019

Отредактированный ответ:

Я не знаю почему, но я просто не мог этого допустить.Казалось, должно быть простое решение.

@ 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);
    }
}
...