ros*_*ead 12 .net javascript browser focus
有没有办法阻止WebBrowser控件导致其父窗体自带到前面?
如果使用InvokeScript方法调用在主父文档中的iframe上调用focus()的JavaScript函数,则会导致窗口直接将其自身带到前面(或至少导致任务栏图标开始闪烁).有没有办法防止这种情况发生?
我找到了问题的临时答案.
当触发WebBrowser的父Form的Deactive事件时,我从其容器中删除WebBrowser,并在再次激活其旧的父窗体时重新添加它.
这有点hacky,但它确实有效.不过,我愿意接受任何更好的建议.
编辑:完整的问题改写,我误解了原始问题
让我们概括一下这个问题:一个你无法控制的控件或组件,可以调用FlashWindow(Win32 API函数)来引起用户的注意.你不希望这样.
通常有两种解决方案:使用API挂钩或消息挂钩.由于API挂钩很复杂且涉及到,我将为Message挂钩提供解决方案.
微软没有用这么多的话来解释它是做什么的FlashWindow.不幸的是,它没有发送特定的消息(比方说WM_FLASH或类似的),这样可以更容易地捕获和废除这种行为.相反,FlashWindow有三件事:
WM_NCACTIVATE第一个闪存的消息WM_NCACTIVATE在定时器到期时发送消息(在接收时WM_SYSTIMER)根据组件调用FlashWindow的方式,这可能是无限期的,直到发生另一次超时,直到它有焦点或只有一次.每个WM_NCACTIVATE消息激活或停用NC区域(标题栏,任务栏上的按钮).它不会改变输入焦点.
防止闪烁的任何解决方案都涉及到一些问题.主要挑战是:
WM_SYSTIMER事件与PostMessage的异步发送的,而不是由接收到的WndProc表单的方法(它仅处理同步消息)WM_NCACTIVATE消息也用于当标题栏或任务栏按钮用户点击设置输入焦点,简单地消除这些消息将具有不希望的副作用WM_SYSTIMER发射,FlashWindow将始终闪烁至少一次.该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);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码已经完全阻止了闪烁.您将不得不添加一些逻辑来更改标题栏,因为完全忽略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
}
}
Run Code Online (Sandbox Code Playgroud)
要激活此messagefilter,只需在表单加载事件中的某处添加以下行:
Application.AddMessageFilter(new MyMessageFilter(this.Handle));
Run Code Online (Sandbox Code Playgroud)
以下常量应放在类级别.它们用于上面的两个代码部分:
public const UInt32 WM_SYSTIMER = 0x0118;
public const UInt32 WM_NCACTIVATE = 0x86;
Run Code Online (Sandbox Code Playgroud)
虽然问题本身是可以解决的,但这并不容易.有了上面的句柄,你应该走得很远.使用滤镜防止闪烁,但第一次"闪光"仍然发生.使用WinProc覆盖也可以防止第一个,但添加一些逻辑以防止您的应用程序表现得太奇怪(即:始终处于非活动状态标题栏,或始终处于活动状态).您已经有一些代码可以与此结合使用来设置一些布尔标志.
在对象中实现IProtectFocus :: AllowFocusChange
在实现IOleClientSite的同一对象上实现IServiceProvider,然后使用暴露IProtectFocus的对象响应Ser_SProtectFocus的IServiceProvider :: QueryService
这是IE7中的一个新界面,因此旧版本运气不佳.
| 归档时间: |
|
| 查看次数: |
11434 次 |
| 最近记录: |