如何在C#中显示前面的表格

时间:2009-06-12 14:49:47

标签: c# forms z-order

民间,

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

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

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

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

所以,请有人知道如何“强制”.NET 3.5表格(通过公平的方式或家禽)来获得焦点?我在想“魔术”的Windows API调用(我知道

Twilight Zone:这只是工作中的一个问题,我们在Windows XP SP3上使用Visual Studio 2008 ...我只是无法重现问题关于Vista Ulimate的Visual C#2008上的SSCCE(见下文)...这很好用。咦? WTF?

另外,我发誓昨天在工作时显示了我运行EXE时的表格,但不是直接从IDE(我刚刚忍受)的F5'(或Ctrl-F5'ed)时...在家里,表格无论如何都表现得很好。 Totaly confusterpating!

它可能相关,也可能不相关,但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年了;所以我有点“知道一些东西”。

任何见解都会受到欢迎......并且感谢大家花时间阅读这篇文章。遗嘱(显然)不是我的强项。

干杯。基思。

11 个答案:

答案 0 :(得分:47)

简单地

yourForm.TopMost = true;

答案 1 :(得分:4)

Form.ShowDialog()有一个重载,它接受一个I​​Win32Window对象。 IWin32Window被视为表单的父窗口。

如果您将父窗口作为System.Windows.Forms.Form,请继续并传递它。如果没有,请获取HWND(可能通过P /调用FindWindow()),并创建一个只返回HWND(More details)的虚拟IWin32Window实现。

答案 2 :(得分:3)

  1. 您说使用Application.Run时效果很好。你为什么不想使用Application.Run呢?
  2. 您是否尝试过调用BringToFront()OnLoad
  3. 中的OnShown

答案 3 :(得分:3)

Form.Activate()在我的案例中工作。

答案 4 :(得分:2)

这是我在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);
    }
}

答案 5 :(得分: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;

    }
}

}

答案 6 :(得分:1)

Activate()也为我工作。

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

答案 7 :(得分:0)

似乎行为是特定于XP ...因此我无法在Vista上重现它。

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

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

Thanx所有你的回答...我可以尝试“少数事情”...我甚至可能明天去办公室试试他们......是的,是的...我有过一次生命,但是我把它换成理发和工作; - )

干杯。基思。

答案 8 :(得分:0)

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

formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();

答案 9 :(得分: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;
}

答案 10 :(得分:-1)

这就是我用来将一个开放表单作为我的应用程序的一部分。 你甚至可以用一个按钮来使用它。但是表格需要打开或者应用程序会中断。

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

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

祝你好运!