民间,
请知道如何从一个不可见的应用程序中显示一个表单,和让它获得焦点(即出现在其他窗口之上)?我正在使用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年了;所以我有点“知道一些东西”。
任何见解都会受到欢迎......并且感谢大家花时间阅读这篇文章。遗嘱(显然)不是我的强项。
干杯。基思。
答案 0 :(得分:47)
简单地
yourForm.TopMost = true;
答案 1 :(得分:4)
Form.ShowDialog()有一个重载,它接受一个IWin32Window对象。 IWin32Window被视为表单的父窗口。
如果您将父窗口作为System.Windows.Forms.Form,请继续并传递它。如果没有,请获取HWND(可能通过P /调用FindWindow()),并创建一个只返回HWND(More details)的虚拟IWin32Window实现。
答案 2 :(得分:3)
Application.Run
时效果很好。你为什么不想使用Application.Run
呢?BringToFront()
或OnLoad
?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();
}
祝你好运!