25

伙计们,

请问有谁知道如何从一个不可见的应用程序中显示一个表单,让它获得焦点(即出现在其他窗口的顶部)?我正在使用 C# .NET 3.5。

我怀疑我采取了“完全错误的方法”......我没有 Application.Run(new TheForm ())而不是我(new TheForm()).ShowModal() ... Form 基本上是一个模态对话,带有几个复选框;一个文本框,以及确定和取消按钮。用户勾选一个复选框并输入描述(或其他内容),然后按 OK,表单消失,进程从表单中读取用户输入,处理它,然后继续处理。

这是有效的,除非当表单显示时它没有获得焦点,而是出现在“主机”应用程序后面,直到您在任务栏(或其他任何内容)中单击它。这是一个最烦人的行为,我预测这会引起很多“支持电话”,而现有的 VB6 版本没有这个问题,所以我在可用性方面倒退了......而且用户不会接受(和他们也不应该)。

所以......我开始认为我需要重新考虑整个shebang......我应该预先显示表单,作为“普通应用程序”并将处理的剩余部分附加到OK-button-click事件。它应该可以工作,但这需要我没有的时间(我已经超过时间/预算)......所以首先我真的需要尝试让当前的方法发挥作用......即使是快速 -肮脏的方法。

那么请有人知道如何“强制”.NET 3.5 表单(通过公平的手段或家禽)来获得焦点吗?我在想“神奇”的 Windows API 调用(我知道

暮光之城:这似乎只是工作中的一个问题,我们在 Windows XP SP3 上使用 Visual Studio 2008 ......我只是未能在 Visual 上用家中的 SSCCE(见下文)重现该问题Vista Ulimate 上的 C# 2008 ......这很好用。嗯?怎么回事?

另外,我发誓昨天在工作时我运行 EXE 时显示了表单,但当我直接从 IDE(我刚刚忍受)F5'ed(或 Ctrl-F5'ed)时却没有......在家里无论哪种方式,表格都很好。完全令人困惑!

它可能相关也可能不相关,但是今天早上,当项目在调试模式下运行并“即时”编辑代码时,Visual Studio 崩溃并烧毁了……它卡住了,我认为这是一个无休止的错误循环消息。错误消息是关于“无法调试这个项目,因为它不是当前项目,或者什么......所以我只是用进程资源管理器将它关闭。它再次启动正常,甚至提出恢复“丢失的"文件,我接受了一个提议。

using System;
using System.Windows.Forms;

namespace ShowFormOnTop {
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());
            Form1 frm = new Form1();
            frm.ShowDialog();
        }
    }
}

背景:我正在将现有的 VB6 实现移植到 .NET……它是一个名为MapInfo的“客户端”GIS 应用程序的“插件” 。现有客户端“工作无形”,我的指示是“使新版本尽可能接近旧版本”,效果很好(经过多年的修补);它只是用不受支持的语言编写的,所以我们需要移植它。

关于我:我基本上是 C# 和 .NET 的菜鸟,虽然我有一个擦屁股证书,但我已经做了 10 年的专业程序员;所以我有点“知道一些东西”。

任何见解都将受到欢迎......感谢大家花时间阅读本文。一致性不是(显然)我的强项。

干杯。基思。

4

11 回答 11

57

简单地

yourForm.TopMost = true;
于 2009-06-12T15:14:55.997 回答
6

Form.Activate()在我的情况下工作。

于 2012-04-18T18:45:35.230 回答
5

有一个重载的 Form.ShowDialog() 需要一个 IWin32Window 对象。该 IWin32Window 被视为窗体的父窗口。

如果您将父窗口作为 System.Windows.Forms.Form,请继续并通过它。如果没有,请获取 HWND(可能通过 P/Invoking 到 FindWindow()),并创建一个仅返回 HWND 的虚拟 IWin32Window 实现(更多详细信息)。

于 2009-06-12T15:16:26.553 回答
3
  1. 您说使用时效果很好Application.Run。那你为什么不想用Application.Run呢?
  2. 您是否尝试过从BringToFront()OnLoad拨打电话OnShown
于 2009-06-12T15:29:55.740 回答
3

Activate()也为我工作。

BringToFront()在这种情况下什么也没做,我不知道为什么。

于 2013-07-09T14:36:21.417 回答
3

这是我经过 20 次不同尝试后编写的最终解决方案:

/* A workaround for showing a form on the foreground and with focus,
 * even if it is run by a process other than the main one
 */
public static void ShowInForeground(this Form form, bool showDialog = false)
{
    if (showDialog)
    {
        //it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
        form.WindowState = FormWindowState.Minimized;
        form.Shown += delegate(Object sender, EventArgs e) {
            ((Form)sender).WindowState = FormWindowState.Normal;
        };
        form.ShowDialog();
    }
    else
    {
        //it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
        form.WindowState = FormWindowState.Minimized;
        form.Show();
        form.WindowState = FormWindowState.Normal;

        //set focus on the first control
        form.SelectNextControl(form.ActiveControl, true, true, true, true);
    }
}
于 2014-03-03T08:16:08.920 回答
1

我已经从我一直在研究的应用程序中破解了这个。我们有一个大型应用程序,它加载了由不同团队编写的一系列模块。我们已经编写了其中一个模块,并且需要在此初始化期间打开一个登录对话框。它被设置为“.TopMost=true”,但这不起作用。

它使用 WindowsFormsSynchronizationContext 打开一个对话框,然后返回对话框的结果。

我很少进行 GUI 编码,并且怀疑这可能是矫枉过正,但如果他们被卡住,它可能会有所帮助。我在理解如何将状态传递给 SendOrPostCallback 时遇到了问题,因为我能找到的所有示例都没有使用它。

这也是从一个工作应用程序中获取的,但我删除了几位代码,并更改了一些细节。抱歉,如果它没有编译。

public bool Dummy()
{

// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();

// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
    // We are in the main thread. Just display the dialog
    DialogResult result = myDialog.ShowDialog();
    return result == DialogResult.OK;
}
else
{
    // Get the window handle of the main window of the calling process
    IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;

    if (windowHandle == IntPtr.Zero)
    {
        // No window displayed yet
        DialogResult result = myDialog.ShowDialog();
        return result == DialogResult.OK;
    }
    else
    {
        // Parent window exists on separate thread
        // We want the dialog box to appear in front of the main window in the calling program
        // We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
        object resultState = null;
        WindowsFormsSynchronizationContext.Current.Send(
            new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);

        if (resultState is DialogResult)
        {
            DialogResult result = (DialogResult) resultState;
            return result == DialogResult.OK;
        }
        else
            return false;

    }
}

}

于 2010-04-29T17:49:00.573 回答
1

这完美地完成了这项工作:

formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
于 2018-04-18T16:59:31.457 回答
0

看来这是特定于 XP 的行为......因此我无法在 Vista 上重现它。

http://www.gamedev.net/community/forums/topic.asp?topic_id=218484

编辑: PS:已经过了我的就寝时间(凌晨 2 点;-)。

谢谢大家的回复……我可以尝试“一些事情”……我什至可能明天去办公室尝试一下……是的,是的……我曾经有过生活,但我把它换了理发和工作;-)

祝大家欢呼。基思。

于 2009-06-12T16:20:18.117 回答
0

我在项目中有一个代码。

private static extern bool SetForegroundWindow(
IntPtr hWnd); 
public static void ShowToFront(Form form)
{
    FormWindowState oldState = form.WindowState;
    form.WindowState = FormWindowState.Minimized;
    form.Show();

    form.Activate();
    form.TopLevel = false;
    form.TopLevel = true;
    form.SelectNextControl(form.ActiveControl, true, true, true, true);
    SetForegroundWindow(form.Handle);
    form.Focus();
    form.WindowState = oldState;
}
于 2018-10-26T03:48:10.617 回答
-1

这就是我用来将作为我的应用程序一部分的开放表单带到前面的方法。您甚至可以通过按钮使用它。但是表单需要打开,否则应用程序将中断。

“YourOpenForm”必须是属性窗口中表单的名称。

    private void button1_Click(object sender, EventArgs e)
    {
        Application.OpenForms["YourOpenForm"].BringToFront();
    }

祝你好运!

于 2013-09-27T18:53:19.567 回答