如何在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()有一个重载,它接受一个IWin32Window对象。 IWin32Window被视为表单的父窗口。
如果您将父窗口作为System.Windows.Forms.Form,请继续并传递它。 如果没有,获取HWND(可能通过P /调用FindWindow()),并创建一个只返回HWND的虚拟IWin32Window实现( 更多细节 )。
- 您说使用
Application.Run
时它可以正常工作。 你为什么不想使用Application.Run
呢? - 你试过从
OnLoad
或OnShown
调用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(); }
祝好运!