有没有办法阻止WebBrowser控件导致其父窗体将自己带到前面?
如果使用InvokeScript方法调用在主父文档中的iframe上调用focus()的JavaScript函数,则会导致窗口直接将其自身带到前面(或至少导致任务栏图标开始闪烁)。有没有办法防止这种情况发生?
我找到了问题的临时答案。
当触发WebBrowser的父Form的Deactive事件时,我从其容器中删除WebBrowser,并在再次激活旧的父窗体时重新添加它。
这有点hacky,但它确实有效。不过,我愿意接受任何更好的建议。
答案 0 :(得分:8)
编辑: 重写完整的问题,我误解了原始问题
让我们概括一下这个问题:一个你无法控制的控件或组件,可以调用FlashWindow
(Win32 API函数)来引起用户的注意。你不希望这样。
通常有两种解决方案:使用API挂钩或消息挂钩。由于API挂钩很复杂且涉及到,我将为Message挂钩提供解决方案。
微软没有用FlashWindow
来解释WM_FLASH
这么多的话。不幸的是,它不会发送特定的消息(比如FlashWindow
或类似的消息),这样可以更容易地捕获和废除此行为。相反,WM_NCACTIVATE
做了三件事:
WM_NCACTIVATE
消息WM_SYSTIMER
时)发送WM_SYSTIMER
消息根据组件调用FlashWindow的方式,这可能是无限期的,直到发生另一次超时,直到它有焦点或只有一次。每个WM_NCACTIVATE消息激活或停用NC区域(标题栏,任务栏上的按钮)。它不会改变输入焦点。
任何防止闪烁的解决方案都涉及到一些问题。主要挑战是:
WndProc
事件与PostMessage异步发送,并且不会被表单的WM_NCACTIVATE
方法接收(它只处理同步消息)WM_SYSTIMER
消息,只需取消这些消息就会产生不必要的副作用WM_SYSTIMER
发射与否。 0x0118
消息未记录。它具有值protected override void WndProc(ref Message m)
{
bool messageHandled = false;
if (m.Msg == WM_NCACTIVATE)
{
// add logic here to determine user action, losing focus etc and set
// messageHandled and m.Result only when user action is not the cause
// of triggering WM_NCACTIVATE
m.Result = IntPtr.Zero;
messageHandled = true;
}
if(!messageHandled)
base.WndProc(ref m);
}
,并在Windows内部用于计时插入符号的闪烁,菜单打开的延迟等。这里用于闪烁之间的时间。
我在此提出的解决方案是进一步发展的基础。它不是一个完整的解决方案,但在许多情况下它解决了这个问题。将以下内容放在表单代码中:
WM_NCACTIVATE
以上代码已经完全阻止了闪烁。您必须添加一些逻辑来更改标题栏,因为完全忽略WM_SYSTIMER
意味着标题栏将始终显示为活动状态,即使它不是。
以下代码为您提供更多控制权。您可以使用它来响应闪烁本身。通常情况下,主窗口不会经常收到FlashWindow
个事件,但您必须尝试是否应该例外。似乎对于wParam
,0xFFF8
始终设置为public class MyMessageFilter : IMessageFilter
{
// an application can have many windows, only filter for one window at the time
IntPtr FilteredHwnd = IntPtr.Zero;
public MyMessageFilter(IntPtr hwnd)
{
this.FilteredHwnd = hwnd;
}
public bool PreFilterMessage(ref Message m)
{
if (this.FilteredHwnd == m.HWnd && m.Msg == WM_SYSTIMER)
return true; // stop handling the message further
else
return false; // all other msgs: handle them
}
}
,但请对其进行试验,因为这在任何地方都没有记录。
Application.AddMessageFilter(new MyMessageFilter(this.Handle));
要激活此messagefilter,只需在表单加载事件中的某处添加以下行:
public const UInt32 WM_SYSTIMER = 0x0118;
public const UInt32 WM_NCACTIVATE = 0x86;
以下常量应放在班级。它们用于上面的两个代码部分:
WinProc
虽然问题本身是可以解决的,但到目前为止并不容易。有了上面的句柄,你应该走得很远。使用滤镜防止闪烁,但第一次“闪光”仍然发生。使用{{1}}覆盖来防止第一个覆盖,但添加一些逻辑以防止您的应用程序表现得太奇怪(即:始终处于非活动标题栏,或始终处于活动状态)。您已经有一些代码可以与此结合使用来设置一些布尔标记。
答案 1 :(得分:5)
在对象中实现IProtectFocus :: AllowFocusChange
在实现IOleClientSite的同一对象上实现IServiceProvider,然后 使用公开IProtectFocus的对象响应Ser_SProtectFocus的IServiceProvider :: QueryService
这是IE7中的一个新界面,因此旧版本运气不佳。