C# 应用程序获得/失去焦点事件

C# 应用程序获得/失去焦点事件,c#,.net,winforms,C#,.net,Winforms,我有一个应用程序,它使用无参数Show()-Methode打开一些子窗口。因此子窗口没有所有者,这使它们可以位于主窗口的后面或前面 现在我想知道整个应用程序是获得焦点还是失去焦点。有没有一个单一的事件可以做到这一点 我尝试了OnActivate/OnDeactivate和OnGotFocus/OnLostFocus,它们只报告单个表单的事件。这意味着当应用程序失去焦点时会触发OnLostFocus事件,但如果另一个窗体处于焦点状态,也会触发OnLostFocus事件。您可以在主窗体中处理,并获得

我有一个应用程序,它使用无参数Show()-Methode打开一些子窗口。因此子窗口没有所有者,这使它们可以位于主窗口的后面或前面

现在我想知道整个应用程序是获得焦点还是失去焦点。有没有一个单一的事件可以做到这一点

我尝试了OnActivate/OnDeactivate和OnGotFocus/OnLostFocus,它们只报告单个表单的事件。这意味着当应用程序失去焦点时会触发OnLostFocus事件,但如果另一个窗体处于焦点状态,也会触发OnLostFocus事件。

您可以在主窗体中处理,并获得有关应用程序激活或停用的通知:

private const int WM_ACTIVATEAPP = 0x1C;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_ACTIVATEAPP)
    {
        if (m.WParam == IntPtr.Zero)
            BeginInvoke(new Action(() => { Text = "Deactivated"; }));
        else
            BeginInvoke(new Action(() => { Text = "Activated"; }));
    }
    base.WndProc(ref m);
}
注意:正如Hans在文章中提到的,在使用上述选项时,应小心不要陷入死锁和无限循环。确保你读了评论


作为另一个选项,您还可以通过处理和事件来检测每个表单的激活或停用。当表单停用时,您可以通过检查
form.ActiveForm
是否有值来检查应用程序是否仍在前台:

private void f_Deactivate(object sender, EventArgs e)
{
    BeginInvoke(new Action(() =>
    {
        if (Form.ActiveForm == null)
            Text = "App Deactivated"; //App deactivated
        else
            Text = "Still Active";   //App is still active
    }));
}

你为什么不订阅所有窗口的焦点事件,因为失去焦点是不明确的。这可能意味着应用程序失去了焦点,或者另一个窗口获得了焦点。我很确定windows窗体在获得焦点时会触发一个事件。另外,如果在他们得到它或丢失它时它会被解雇,我想.NET至少会在eventargs中有信息告诉你什么是什么。如果没有,我不知道如何帮助有一个专门的Windows消息,WM_ACTIVATEAPP。由于这是一条危险的消息,所以在Winforms中故意不公开它,因为操作系统窗口管理器保留了一个内部锁,以防止再次进入问题,因此有很多方法可以攻击您的左脚。如果你的程序死锁,那么你做的太多了,使用BeginInvoke()是一种通过故意延迟代码来消除死锁的方法。这个答案应该指出该消息的危险。我在这个问题上添加了评论,考虑采用它,并将评论标记为“不再需要”。