C# 在具有多个顶级表单的应用程序中,如何防止用户认为它由于模式对话框而被锁定?

C# 在具有多个顶级表单的应用程序中,如何防止用户认为它由于模式对话框而被锁定?,c#,.net,winforms,modal-dialog,topmost,C#,.net,Winforms,Modal Dialog,Topmost,在具有多个顶级窗口的应用程序中,带模式对话框的正常WinForms行为似乎有问题。我很好奇是否有人制定了更有效的方法。让我解释一下 情况: 当您执行dialog.ShowDialog(父窗口)时,用户单击或激活父窗口的任何尝试都会导致激活模式对话框,并将其闪烁,以便清楚地显示“您必须首先处理此问题”。太好了 如果用户点击应用程序中的另一个顶级窗口,它不会做任何事情……它不会闪烁模式对话框……它不会给你警告……它甚至不会打开模式对话框……如果你的计算机没有静音,你最多可能会听到一声蜂鸣。它唯一正确

在具有多个顶级窗口的应用程序中,带模式对话框的正常WinForms行为似乎有问题。我很好奇是否有人制定了更有效的方法。让我解释一下

情况:

当您执行dialog.ShowDialog(父窗口)时,用户单击或激活父窗口的任何尝试都会导致激活模式对话框,并将其闪烁,以便清楚地显示“您必须首先处理此问题”。太好了

如果用户点击应用程序中的另一个顶级窗口,它不会做任何事情……它不会闪烁模式对话框……它不会给你警告……它甚至不会打开模式对话框……如果你的计算机没有静音,你最多可能会听到一声蜂鸣。它唯一正确的地方是它不会激活或打开你正在点击的窗口…这至少给了用户一个线索

如果用户使用任务栏选择其他顶级窗口之一,现在它将把它带到前面!它仍然不会激活,但现在它可能完全覆盖了该模式对话框。任何与该顶级窗口交互的尝试都将失败。好像锁上了。因此,许多用户认为我们的应用程序已锁定…他们最终在任务管理器中杀死我们的应用程序并重新启动!并将其作为bug报告给我们。事实上,他们刚刚打开了一个模态对话框,需要返回到它

问题:

有没有办法点击或激活我们应用程序中的任何窗口,使模式对话框出现在前面并闪烁(就像它的父窗口现在会做的那样)

我能以某种方式成为一组窗口的父对象吗

我们考虑过让所有的模态对话框都在最上面…但是我们的一些模态对话框打开了其他窗口…一些不应该在最上面,所以管理最上面变得很复杂。此外,它与其他应用程序不友好

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

您可以处理表单事件,然后使用“检查是否有打开的模式表单且模式表单不是当前表单”,然后激活模式表单:

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(); 
    }
}
private void Form1\u已激活(对象发送方,事件参数e)
{
var f=Application.OpenForms.Cast(),其中(x=>x.Modal.LastOrDefault();
如果(f!=null&&f!=this)
{
如果(f.WindowState==FormWindowState.Minimized)
f、 WindowState=FormWindowState.Normal;
f、 激活();
}
}

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

此答案受上述Reza答案的启发,但Reza的答案似乎无法处理模式对话框打开非模式表单的情况。现在,我们从基本表单的激活事件处理程序调用以下函数

    /// <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;
    }
//
///在OpenForms中查找justActivatedForm之后的最后一个模态表单;
///如果它找到它,那么它会激活它并返回它。否则,它将返回null。
/// 
///刚刚激活的表单,提示检查模态。
///返回justActivatedForm之后的最后一个模态窗体;或者,如果不存在这样的值,则为空。
公共静态表单ActivateLastModalForm(表单justActivatedForm)
{
//在justActivatedForm之后是否有模态形式?如果是,则获取最后一个模态形式。
Form lastmodel=null;
bool foundJustActivatedForm=false;
foreach(Application.OpenForms中的表单)
{
如果(foundJustActivatedForm)
{
如果(形式模态)
lastModal=形式;
}
else if(form==justActivatedForm)
{
foundJustActivatedForm=true;
}
}
//如果在justActivatedForm之后找到最后一个模态窗体,请将其激活
if(lastmodel!=null)
{
LOG.Focus(“找到模态形式,激活它…”);
如果(lastModal.WindowsState==FormWindowsState.Minimized)
lastModal.WindowsState=FormWindowsState.Normal;
lastModal.Activate();
}
返回模式;
}

如果您发现此解决方案中存在任何缺陷,请告知我们

我认为最好的办法是尽量减少显示的单独窗口和模式对话框的数量,这样就不会出现问题。谢谢!这让我找到了我刚刚发布的解决方案,它似乎运行良好。(你的代码保持原样,一些被模态对话框激活但本身不是模态的表单将被破坏…变得没有响应。)但是你的回答给了我我所缺少的关键成分。谢谢!!