在具有多个 top-level 表单的应用程序中,您如何防止用户认为它由于模态对话框而被锁定?

In an app with multiple top-level forms, how do you prevent the user from thinking it locked up due to a modal dialog?

在具有多个 top-level windows 的应用程序中,模式对话框的正常 WinForms 行为似乎有问题。我很好奇是否有人开发出更有效的方法。让我解释一下……

情况:

当您执行 dialog.ShowDialog(parent) 时,用户单击或激活该 parent window 的任何尝试都会导致激活模态对话框,并且闪烁它,清楚地表明“你必须先处理这个。”太棒了

如果用户在您的应用中点击另一个 top-level windows,它不会执行任何操作……它不会闪烁模态对话框……它不会提供你一个警告......它甚至没有提出模态对话框......如果你没有将计算机静音,你可能得到的最多是哔哔声。它唯一做对的是它不会激活或提示您正在单击的 window ……这至少给了用户一个线索。

如果用户使用任务栏 select 您的另一个 top-level windows,现在它将把它带到前面!它仍然不会激活,但现在它可能会完全覆盖该模式对话框。任何与 top-level window 交互的尝试都会失败。好像锁起来了因此,许多用户认为我们的应用程序已锁定……他们最终在任务管理器中终止了我们的应用程序并重新启动!并将其作为错误报告给我们。事实上,他们刚刚打开了一个模态对话框,需要 return。

问题:

有什么方法可以在我们的应用程序中点击或激活任何 window 来使模态对话框出现在前面并闪烁(就像它的 parent window 一样)现在)?

我可以parent到一组windows吗?

我们考虑过将所有模态对话框置于最顶层……但是我们的一些模态对话框打开了其他 windows……有些不应该位于最顶层,因此管理最顶层变得很复杂。而且它对其他应用程序不友好。

在具有多个 top-level 表单的应用程序中,您如何防止用户认为它由于隐藏的模态对话框而被锁定?

您可以处理Activated event of your forms and then using Application.OpenForms检查是否有打开的模态窗体并且模态窗体不是当前窗体,然后激活模态窗体:

private void Form1_Activated(object sender, EventArgs e)
{
    var f = Application.OpenForms.Cast<Form>().Where(x => x.Modal).LastOrDefault();
    if (f != null && f != this)
    {
        if (f.WindowState == FormWindowState.Minimized)
            f.WindowState = FormWindowState.Normal;

        f.Activate(); 
    }
}

您可以将逻辑放在基本表单中,或者在打开表单时,将此类处理程序附加到其 Activated 事件。

这个答案的灵感来自于上面 Reza 的答案,但是 Reza 的答案似乎没有处理模态对话框打开非模态窗体的情况。现在,我们从基本表单的 Activated 事件处理程序中调用以下函数。

    /// <summary>
    /// Looks for the last Modal Form in OpenForms that is AFTER justActivatedForm;
    /// if it finds it, then it Activates it and returns it. Otherwise, it returns null.
    /// </summary>
    /// <param name="justActivatedForm">The Form that was just Activated, prompting this check for Modal.</param>
    /// <returns>Returns the last Modal Form AFTER justActivatedForm; or null if no such exists.</returns>
    public static Form ActivateLastModalForm(Form justActivatedForm)
    {
        // Is there a Modal Form after justActivatedForm?  If so, get the last Modal Form.
        Form lastModal = null;
        bool foundJustActivatedForm = false;
        foreach (Form form in Application.OpenForms)
        {
            if (foundJustActivatedForm)
            {
                if (form.Modal)
                    lastModal = form;
            }
            else if (form == justActivatedForm)
            {
                foundJustActivatedForm = true;
            }
        }

        // If last Modal Form is found after justActivatedForm, Activate it
        if (lastModal != null)
        {
            LOG.Focus("Found Modal Form. Activating it...");
            if (lastModal.WindowState == FormWindowState.Minimized)
                lastModal.WindowState = FormWindowState.Normal;
            lastModal.Activate();
        }

        return lastModal;
    }

如果您发现此解决方案有任何缺陷,请告诉我们!