有没有一种方法可以阻止WebBrowser控件导致其父窗体显示在最前面?
如果使用InvokeScript方法调用在主父文档中的iframe上调用focus()的JavaScript函数,则将导致窗口直接将其自身置于最前面(或者至少导致任务栏图标开始闪烁)。有办法防止这种情况发生吗?
更新:
我已经找到问题的临时答案。
当WebBrowser的父窗体的Deactive事件被触发时,我将WebBrowser从其容器中删除,并在再次激活其旧的父窗体时重新添加它。
这有点hacky,但是可以用。不过,我愿意接受任何更好的建议。
最佳答案
编辑:完整问题被重写,我误解了原始问题
我们来概括一下这个问题:您没有控件的控件或组件可以调用FlashWindow
(Win32 API函数)来引起用户的注意。你不要那样
通常有两种解决方案:使用API挂钩或消息挂钩。由于API挂钩非常复杂且涉及很多,因此我将介绍消息挂钩的解决方案。
Flash窗口
微软没有用太多的词来解释FlashWindow
是做什么的。不幸的是,它没有发送特定的消息(例如WM_FLASH
或类似消息),这会使捕获和废除此行为变得更加容易。相反,FlashWindow
做三件事:
WM_NCACTIVATE
消息WM_NCACTIVATE
时)发送WM_SYSTIMER
消息根据组件调用FlashWindow的方式,这可以是不确定的,直到发生另一个超时,直到获得焦点或只有一次。每条WM_NCACTIVATE消息都会激活或禁用NC区域(标题栏,任务栏上的按钮)。它不会改变输入焦点。
挑战
涉及任何防止闪烁的解决方案。主要挑战是:
WM_SYSTIMER
事件与PostMessage异步发送,但Form的WndProc
方法未接收到它(它仅处理同步消息)WM_NCACTIVATE
消息,仅取消这些消息将产生有害的副作用WM_SYSTIMER
。 WM_SYSTIMER
消息未记录。它具有0x0118
值,Windows内部使用它来计时插入符号的闪烁,菜单打开的延迟等时间。在此,它用于两次闪烁之间的时间。解
我在这里介绍的解决方案是进一步开发的基础。它不是一个完整的解决方案,但在许多情况下都可以解决该问题。将以下内容放在表单代码中:
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);
}
上面的代码已经完全阻止了闪烁。您必须添加一些逻辑来更改标题栏,因为完全忽略
WM_NCACTIVATE
意味着标题栏将一直保持 Activity 状态,即使没有激活也是如此。以下代码为您提供了更多控制。您可以使用它来对闪烁本身使用react。通常,主窗口不会如此频繁地接收
WM_SYSTIMER
事件,但是您必须尝试是否应该设置异常(exception)。似乎对于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));
以下常量应放在类级别。它们在以上两个代码节中都使用:
public const UInt32 WM_SYSTIMER = 0x0118;
public const UInt32 WM_NCACTIVATE = 0x86;
结论
尽管问题本身是可以解决的,但到目前为止并非易事。使用上述句柄,您应该走得很远。使用过滤器来防止闪烁,但随后仍会发生第一个“闪烁”。也可以使用
WinProc
替代来阻止第一个,但要添加一些逻辑以防止您的应用程序表现得异常(即:标题栏始终处于非 Activity 状态,或始终处于 Activity 状态)。您已经有一些代码,可以将其与此结合以设置一些 bool(boolean) 标志。