繁体   English   中英

当我将可见的正确设置为true时,如何防止我的C#winforms应用程序窃取焦点?

[英]How to prevent my C# winforms application from stealing focus when I set the visible properly to true?

我有一个在后台运行的C#winforms应用程序,正在监听要按下的热键。 当按下热键时,我的表格会短暂出现。 表单始终在运行,但设置为隐藏,直到我收到热键事件,此时我将visible属性设置为true。 代码如下所示:

void hook_volumeDown(object sender, KeyPressedEventArgs e)
{
    this.Visible = true;
}

应该注意,此表单的最顶层属性设置为true。

真正奇怪的是,在我的C#应用​​程序从另一个应用程序中窃取焦点后,它将再也不会这样做了。 例如:我启动我的应用程序,然后启动一些像Team Fortress 2这样的fullscreep应用程序。然后我按下我的热键。 Team Fortress 2最小化,我看到了我的形式。 然而,然后,我可以恢复TF2,并再次按我的热键我想要的(具有所需的效果),TF2将保持聚焦。

无论如何,我正在寻找解决这个问题的方法。 我在这里发现了很多关于类似问题的问题,但是所有问题都与创建/启动新表单有关,而不是使现有表单可见(除非我遗漏了一些东西)。 我可以重新编写应用程序,以便在每次需要时创建一个新表单,但这需要创建另一个表单,以便一直看不见只是为了等待热键事件,所以我宁愿保持原样。

有任何想法吗?

我认为你的问题与Visible = true在第一次和后续调用之间表现不同的事实有关。 第一次调用visible并且尚未创建窗口句柄时,通过调用CreateWindowEx创建Window,它具有一些控制窗口行为方式的样式参数。 我认为您需要确保使用样式WS_EX_NOACTIVATE创建窗口,您可以通过覆盖CreateParams来完成。

其他要试试的东西:

1)ShowWindow函数(由Visible = true使用)在第一次调用时忽略焦点参数( http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx )该程序提供了STARTUPINFO结构。 深入研究反射器并找出Form类是否提供STARTUPINFO结构,如果是,则如何操作它。

2)Form有一个ShowWithoutActivation属性,可以覆盖并设置为true,你有没有覆盖它?

对不起“没有确切的答案”,但我希望这至少可以为您提供一些进一步调查的起点。 祝好运。

看到你的函数中使用的KeyPressedEventArgs看起来奇怪。 热键可以通过P / Invoking RegisterHotKey()API函数实现。 当按下热键时,它会向您的窗口发送一条消息。 这是一个在启动时不可见的表单示例,当您按下热键时弹出。 在这种情况下,按Ctrl + Alt + U:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        private const int MYKEYID = 0;    // In case you want to register more than one...
        public Form1() {
            InitializeComponent();
            this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID);
        }
        protected override void SetVisibleCore(bool value) {
            if (value && !this.IsHandleCreated) {
                this.CreateHandle();
                RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U);
                value = false;
            }
            base.SetVisibleCore(value);
        }
        protected override void WndProc(ref Message m) {
            if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) {
                this.Visible = true;
                if (this.WindowState == FormWindowState.Minimized)
                    this.WindowState = FormWindowState.Normal;
                SetForegroundWindow(this.Handle);
            }
            base.WndProc(ref m);
        }
        // P/Invoke declarations
        private const int WM_HOTKEY = 0x312;
        private const int MOD_ALT = 1;
        private const int MOD_CONTROL = 2;
        private const int MOD_SHIFT = 4;
        [DllImport("user32.dll")]
        private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk);
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
    }
}

请注意,SetForegroundWindow()函数可能是您在问题中描述的问题的根源。 当用户正在使用其他窗口时,Windows不允许应用程序在用户的脸上推动窗口。 至少几秒钟的不活动必须在允许窗口窃取焦点之前到期。 使用给定的代码,很容易看到,表单的任务栏按钮将闪烁。 避免将ShowInTaskbar属性设置为false。 没有必要使用此代码,任务栏按钮将不会显示,直到按下热键。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM