C# 打开流程(记事本)后如何将焦点设置回窗体?
我使用C# 打开流程(记事本)后如何将焦点设置回窗体?,c#,winforms,process,focus,windows-shell,C#,Winforms,Process,Focus,Windows Shell,我使用Process.Start()从程序中打开记事本,但新打开的记事本覆盖了屏幕。但我确实希望我的应用程序保持其焦点 同样地,我(使用相同的Process.Start)打开MS Excel和Word,但为了让焦点回到我的表单,我需要写的是: this.Focus(); 但记事本的怪癖是:我打开记事本(以及所有其他类似的过程) 现在记事本成为焦点 我试过这些: this.Activate(),this.Focus(),不用说 另一个较长的解决方案来自 所有这些仍然保持着对记事本的关注。为什
Process.Start()
从程序中打开记事本,但新打开的记事本覆盖了屏幕。但我确实希望我的应用程序保持其焦点
同样地,我(使用相同的Process.Start)打开MS Excel和Word,但为了让焦点回到我的表单,我需要写的是:
this.Focus();
但记事本的怪癖是:我打开记事本(以及所有其他类似的过程)
现在记事本成为焦点
我试过这些:
this.Activate()
,this.Focus()
,不用说编辑:我最多可以打开记事本最小化,但在尝试了以上所有代码后,它仍然无法将焦点放在表单上。记事本打开时最小化,但焦点仍在记事本上(我们在windows xp中有时会看到这种情况),窗体将失去焦点。我也遇到了同样的问题,我最终以编程方式调用alt tab:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private void alttab()
{
uint WM_SYSCOMMAND = 0x0112;
int SC_PREVWINDOW = 0xF050;
PostMessage(Process.GetCurrentProcess().MainWindowHandle, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
}
//编辑:您应该使用process.MainWindowHandle,而不是Windows。Windows阻止应用程序将其窗口推到用户的脸上,您在工作中看到了这一点。应用程序窃取焦点的确切规则记录在AllowSetForeGroundIndow()的MSDN文档中 围绕此限制的后门是AttachThreadInput()函数。这段代码运行得很好,我在查找拥有前台窗口的线程的线程ID时使用了快捷方式。对于记事本来说已经足够好了,可能不适合其他应用。请注意,雷蒙德·陈不赞成这种黑客行为
private void button1_Click(object sender, EventArgs e) {
var prc = Process.Start("notepad.exe");
prc.WaitForInputIdle();
int tid = GetCurrentThreadId();
int tidTo = prc.Threads[0].Id;
if (!AttachThreadInput(tid, tidTo, true)) throw new Win32Exception();
this.BringToFront();
AttachThreadInput(tid, tidTo, false);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool AttachThreadInput(int tid, int tidTo, bool attach);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
我在互联网上尝试了几乎所有的东西(非常确定:))。充其量我可以把我的表格放在所有其他表格之上,但没有重点(按照@Hans Passant的方法)。通过大量的代码,我不知何故觉得这并不容易。因此,我总是将
setForeGroundIndow()
与其他代码块一起使用。从来没有想过仅仅setforegroundindow()
就能做到这一点
这起作用了
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
Process process = new Process();
process.StartInfo.FileName = @...\abc.log";
process.Start();
process.WaitForInputIdle(); //this is the key!!
SetForegroundWindow(this.Handle);
}
有时,此方法将焦点放在父窗体上(在我所需窗体是其父窗体的模态子窗体的情况下);在这种情况下,只需在最后一行添加this.Focus()
即使这样也行得通:
Microsoft.VisualBasic.Interaction.Shell(@"notepad.exe D:\abc.log",
Microsoft.VisualBasic.AppWinStyle.NormalNoFocus);
由提供的解决方案请尝试以下方法:
public partial class MainForm : Form
{
private ShowForm showForm;
public MainForm()
{
InitializeComponent();
}
private void showButton_Click(object sender, EventArgs e)
{
this.showForm = new ShowForm();
this.showForm.FormClosed += showForm_FormClosed;
this.showForm.Show(this);
}
private void showForm_FormClosed(object sender, FormClosedEventArgs e)
{
this.Focus();
}
}
如果要启动流程并将焦点放回表单,请使用最小化状态启动该流程,如下所示:
Dim psi As New ProcessStartInfo("notepad")
psi.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(psi)
在最小化状态下启动窗口可以吗?可以,但仍然不能工作。我会在我的问题中更新你试过这个吗?谢谢但我怀疑BringToFront是否真的在这里有效。这不只是一种使控件在另一个控件上方可见的措施吗?不是吗。激活是一个更好的选择吗?还有谁是陈雷蒙?要批准这个吗BringToFront()调用setForeGroundIndow(),只需编写代码即可轻松查看。Raymond Chen是一名微软程序员,拥有一个广受欢迎的博客。把答案也贴在这里,我不想惹他生气。Hans:这段代码允许我的表单显示在记事本上,但现在的焦点既不在表单上,也不在记事本上。我试过这个。激活这个。聚焦,但应用程序上仍然没有聚焦。这对我们的客户来说是一个严肃的要求。这是如何回答这个问题的?这是有效的,并回答了所问的问题,但更好的解决方案是首先防止启动的流程窃取焦点,而不是让调用方在失去焦点后重新获得焦点。看,实际上,我错过了你的第二个命令已经做了我在之前的评论中建议的事情,这是由和它的旗帜提供的。
Microsoft.VisualBasic.Interaction.Shell(@"notepad.exe D:\abc.log",
Microsoft.VisualBasic.AppWinStyle.NormalNoFocus);
public partial class MainForm : Form
{
private ShowForm showForm;
public MainForm()
{
InitializeComponent();
}
private void showButton_Click(object sender, EventArgs e)
{
this.showForm = new ShowForm();
this.showForm.FormClosed += showForm_FormClosed;
this.showForm.Show(this);
}
private void showForm_FormClosed(object sender, FormClosedEventArgs e)
{
this.Focus();
}
}
Dim psi As New ProcessStartInfo("notepad")
psi.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(psi)