问题描述
我在让通知框在 c# 中正确运行时遇到了一些问题.基本上我在屏幕的右下角显示一个无边框的表格,它显示一条消息几秒钟然后消失.问题是我需要它出现在其他窗口的顶部而它永远无法窃取焦点.理想情况下,我希望它是纯托管代码,尽管查看类似的示例我怀疑这是可能的.
I'm having some issues getting a notification box to behave correctly in c#. Basically I'm showing a boarderless form in the lower right hand side of the screen, which displays a message for a few seconds and then disappears. The problem is that I need it to appear on top of other windows without it ever being able to steal focus. Ideally, I want it to be purely managed code, although looking through similar examples I doubt this will be possible.
目前我正在防止它在使用覆盖调用 Form.Show() 时窃取焦点:
At the moment I'm preventing it from stealing focus when calling Form.Show() with an override:
protected override bool ShowWithoutActivation // stops the window from stealing focus
{
get { return true; }
}
然后忽略鼠标点击:
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);
}
但是我发现如果我将这些与 TopMost = true(我需要)结合使用,它无论如何都会获得焦点,如果所有其他窗口都最小化,它也会获得焦点.
However I find that if I use these in conjunction with TopMost = true (which I need), it gains focus anyway, and if all other windows are minimised, it also gains focus.
那么,有什么方法可以阻止表单获得焦点(无论是通过鼠标单击、alt-tab 等),同时仍然是最重要/第二个最重要的表单?即使只是立即将焦点返回到它窃取它的窗口也会起作用(尽管会引入闪烁).
So, is there any way to flat out prevent a form from ever gaining focus (whether via mouse click, alt-tab, etc), while still being the top most/second top most form? Even just giving focus immediately back to the window it stole it from would work (although introduce flickering).
任何建议将不胜感激,我真的坚持这一点.
Any suggestions would be greatly appreciated, I'm really stuck with this.
好的,所以我终于设法使用:
Ok, so I finally managed to get this working using:
protected override bool ShowWithoutActivation // stops the window from stealing focus
{
get { return true; }
}
// and
const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams param = base.CreateParams;
param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
return param;
}
}
// and
[DllImport("user32.dll")]
private extern static IntPtr SetActiveWindow(IntPtr handle);
private const int WM_ACTIVATE = 6;
private const int WA_INACTIVE = 0;
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
return;
}
if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
{
if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
{
if (m.LParam != IntPtr.Zero)
{
SetActiveWindow(m.LParam);
}
else
{
// Could not find sender, just in-activate it.
SetActiveWindow(IntPtr.Zero);
}
}
}
我还在 GotFocus 事件中添加了 Form.Hide(),这样即使它以某种方式获得焦点,它也会关闭并尽快离开用户.
I also added Form.Hide() to the GotFocus event so that even if it does somehow get focus, it simply closes and gets out of the users way asap.
此外,如果有人想知道,可以在 WINUSER.H 中找到所有窗口样式等的常量,其在线地址为 http://www.woodmann.com/fravia/sources/WINUSER.H 如果找不到.
Also, if anyone is wondering, the constants for all the window styles etc. can be found in WINUSER.H, its online at http://www.woodmann.com/fravia/sources/WINUSER.H if you can't find it.
然而,如果有人能看到一种更优雅的方式来做到这一点,我们将不胜感激.
However, if anyone can see a more elegant way of doing this, it would be appreciated.
推荐答案
在 WPF 中试试这个:
In WPF try this:
ShowActivated="False"
这篇关于通知窗口 - 防止窗口获得焦点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!