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

伙计们,

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

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

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

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

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

Twilight Zone:这似乎只是工作中的一个问题,我们在Windows XP SP3上使用Visual Studio 2008 …我刚刚在家中无法使用SSCCE(见下文)重现问题关于Vista Ulimate的C#2008 ……这很好用。 咦? 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年了; 所以我有点“知道一些东西”。

任何见解都是最受欢迎的……谢谢大家花时间阅读这篇文章。 怜悯(显然)不是我的强项。

干杯。 基思。

只是

 yourForm.TopMost = true; 

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

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

  1. 您说使用Application.Run时它可以正常工作。 你为什么不想使用Application.Run呢?
  2. 你试过从OnLoadOnShown调用BringToFront()吗?

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

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

我从我一直在努力的应用程序中攻击了这个。 我们有一个大型应用程序,可以加载由不同团队编写的一系列模块。 我们编写了其中一个模块,并且需要在初始化期间打开登录对话框。 它设置为’.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; } } 

}

Activate()也为我工作。

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

看起来行为是特定于XP …因此我不能在Vista上重现它。

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

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

Thanx所有你的回答…有一些“我可以尝试的东西”…我甚至可能明天去办公室试试他们……是的,是的…我有过一次生命,但我交易了它理发和工作;-)

干杯全都。 基思。

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

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

我在项目中得到了一个代码。

 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; } 

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

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

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

祝好运!