热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WebBrowser控制键盘和焦点行为-WebBrowsercontrolkeyboardandfocusbehavior

Apparently,therearesomeseriouskeyboardandfocusissueswithWPFWebBrowsercontrol.Iveputt

Apparently, there are some serious keyboard and focus issues with WPF WebBrowser control. I've put together a trivial WPF app, just a WebBrowser and two buttons. The app loads a very basic editable HTML markup (some text) and demonstrates the following:

显然,WPF WebBrowser控件存在一些严重的键盘和焦点问题。我整合了一个微不足道的WPF应用程序,一个网络浏览器和两个按钮。该应用程序加载一个非常基本的可编辑HTML标记(一些文本),并演示以下内容:

  • Tabbing is misbehaving. User needs to hit Tab twice to see the caret (text cursor) inside WebBrowser and be able to type.

    跨栏是行为不端。用户需要按Tab键两次,才能在WebBrowser中看到caret(文本光标),并能够键入。

  • When user switches away from the app (e.g., with Alt-Tab), then goes back, the caret is gone and she is unable to type at all. A physical mouse click into the WebBrowser's window client area is required to get back the caret and keystrokes.

    当用户离开应用程序时(例如,使用Alt-Tab),然后返回,插入符号就消失了,她根本无法输入。要取回插入符号和击键,需要在WebBrowser的窗口客户端区域中单击一个物理鼠标。

  • Inconsistently, a dotted focus rectangle shows up around WebBrowser (when tabbing, but not when clicking). I could not find a way to get rid of it (FocusVisual does not help).

    不一致的是,在WebBrowser周围会出现一个虚线焦点矩形(在制表时显示,但在单击时不显示)。我找不到摆脱它的方法(FocusVisual没有帮助)。

  • Internally, WebBrowser never receives the focus. That's true for both logical focus (FocusManager) and input focus (Keyboard). The Keyboard.GotKeyboardFocusEvent and FocusManager.GotFocusEvent events never get fired for WebBrowser (although they both do for buttons in the same focus scope). Even when the caret is inside WebBrowser, FocusManager.GetFocusedElement(mainWindow) points to a previously focused element (a button) and Keyboard.FocusedElement is null. At the same time, ((IKeyboardInputSink)this.webBrowser).HasFocusWithin() returns true.

    在内部,WebBrowser不会收到焦点。对于逻辑焦点(FocusManager)和输入焦点(键盘)都是如此。键盘。GotKeyboardFocusEvent FocusManager。GotFocusEvent事件不会因为WebBrowser而被触发(尽管它们都在同一个焦点范围内对按钮进行操作)。即使插入符号在WebBrowser中,FocusManager.GetFocusedElement(mainWindow)也指向一个先前聚焦的元素(一个按钮)和键盘。FocusedElement是null。同时,((IKeyboardInputSink)this.webBrowser). hasfocuswithin()返回true。

I'd say, such behaviour is almost too dysfunctional to be true, but that's how it works. I could probably come up with some hacks to fix it and bring it in row with native WPF controls like TextBox. Still I hope, maybe I'm missing something obscure yet simple here. Has anyone dealt with a similar problem? Any suggestions on how to fix this would be greatly appreciated.

我得说,这种行为几乎是不正常的,不可能是真的,但它就是这样运作的。我可能会想出一些技巧来修复它,并将它与文本框之类的本地WPF控件放在一起。我仍然希望,也许我在这里漏掉了一些模糊但简单的东西。有人处理过类似的问题吗?对于如何解决这一问题,我们将非常感谢。

At this point, I'm inclined to develop an in-house WPF wrapper for WebBrowser ActiveX Control, based upon HwndHost. We are also considering other alternatives to WebBrowser, such as Chromium Embedded Framework (CEF).

在这一点上,我倾向于开发基于HwndHost的WebBrowser ActiveX控件的内部WPF包装器。我们还在考虑web浏览器的其他替代品,比如Chromium嵌入式框架(CEF)。

The VS2012 project can be downloaded from here in case someone wants to play with it.

VS2012项目可以从这里下载,以防有人想玩它。

This is XAML:

这是XAML:



    
        

        

        

This is C# code, it has a bunch of diagnostic traces to show how focus/keyboard events are routed and where the focus is:

这是c#代码,它有许多诊断跟踪,显示焦点/键盘事件是如何路由的,焦点在哪里:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;

namespace WpfWebBrowserTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // watch these events for diagnostics
            EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.PreviewKeyDownEvent, new KeyEventHandler(MainWindow_PreviewKeyDown));
            EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(MainWindow_GotKeyboardFocus));
            EventManager.RegisterClassHandler(typeof(UIElement), FocusManager.GotFocusEvent, new RoutedEventHandler(MainWindow_GotFocus));
        }

        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            // load the browser
            this.webBrowser.NavigateToString("Line 1
Line 3
Line 3
"); this.btnLoad.IsChecked = true; } private void btnClose_Click(object sender, RoutedEventArgs e) { // close the form if (MessageBox.Show("Close it?", this.Title, MessageBoxButton.YesNo) == MessageBoxResult.Yes) this.Close(); } // Diagnostic events void MainWindow_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused()); } void MainWindow_GotFocus(object sender, RoutedEventArgs e) { Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused()); } void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) { Debug.Print("{0}, key: {1}, source: {2}, {3}", FormatMethodName(), e.Key.ToString(), FormatType(e.Source), FormatFocused()); } // Debug output formatting helpers string FormatFocused() { // show current focus and keyboard focus return String.Format("Focus: {0}, Keyboard focus: {1}, webBrowser.HasFocusWithin: {2}", FormatType(FocusManager.GetFocusedElement(this)), FormatType(Keyboard.FocusedElement), ((System.Windows.Interop.IKeyboardInputSink)this.webBrowser).HasFocusWithin()); } string FormatType(object p) { string result = p != null ? String.Concat('*', p.GetType().Name, '*') : "null"; if (p == this.webBrowser ) result += "!!"; return result; } static string FormatMethodName() { return new StackTrace(true).GetFrame(1).GetMethod().Name; } } }

[UPDATE] The situation doesn't get better if I host WinForms WebBrowser (in place of, or side-by-side with WPF WebBrowser):

[更新]如果我托管WinForms WebBrowser(代替WPF WebBrowser,或与WPF WebBrowser并行),情况不会变得更好:


    

    

    
        
    

    

The only improvement is that I do see focus events on WindowsFormsHost.

唯一的改进是,我确实看到了WindowsFormsHost上的焦点事件。

[UPDATE] An extreme case: two WebBrowser controls with two carets showing at the same time:

[更新]一个极端的情况:两个WebBrowser控件同时显示两个carets:


    

    
    

    

This also illustrates that the focus handling issue is not specific to cOntentEditable=true content.

这也说明了焦点处理问题并不是针对cOntentEditable=true content的。

2 个解决方案

#1


5  

The reason it behaves this way is related to the fact that it's an ActiveX control which itself is a fully windows class (it handles mouse and keyboard interaction). In fact much of the time you see the component used you'll find it is the main component taking up a full window because of this. It doesn't have to be done that way but it presents issues.

它这样做的原因与它是一个ActiveX控件有关,它本身就是一个完整的windows类(它处理鼠标和键盘交互)。事实上,大多数时候你看到的组件,你会发现它是主组件占据了一个完整的窗口。不需要那样做,但它会带来问题。

Here's a forum discussing the exact same issue and it's causes can be clarified by reading the last commentators article links:

这里有一个讨论相同问题的论坛,其原因可以通过阅读最后的评论文章链接来澄清:

http://social.msdn.microsoft.com/Forums/vstudio/en-US/1b50fec6-6596-4c0a-9191-32cd059f18f7/focus-issues-with-systemwindowscontrolswebbrowser

http://social.msdn.microsoft.com/forums/vstudio/en us/1b50fec6 - 6596 - 4 - c0a - 9191 - 32 - cd059f18f7/focus——问题————systemwindowscontrolswebbrowser

To outline the issues you're having

列出你所遇到的问题

  • Tabbing is misbehaving. User needs to hit Tab twice to see the caret (text cursor) inside WebBrowser and be able to type.

    跨栏是行为不端。用户需要按Tab键两次,才能在WebBrowser中看到caret(文本光标),并能够键入。

    that's because the browser control itself is a window which can be tabbed to. It doesn't "forward" the tab to it's child elements immediately.

    这是因为浏览器控件本身是一个窗口,可以对其进行制表。它不会立即将选项卡“转发”给它的子元素。

    One way to change this would be to handle the WM message for the component itself but keep in mind that doing so gets tricky when you want the "child" document inside of it to be able to handle messages.

    改变这一点的一种方法是处理组件本身的WM消息,但是请记住,当您希望组件内部的“子”文档能够处理消息时,这样做是很困难的。

    See: Prevent WebBrowser control from stealing focus? specifically the "answer". Although their answer doesn't account that you can control whether the component interacts through dialogs with the user by setting the Silent property (may or may not exist in the WPF control... not sure)

    注意:防止WebBrowser控件窃取焦点?特别是“回答”。尽管他们的答案并不说明您可以通过设置静默属性(WPF控件中可能存在也可能不存在)来控制组件是否通过对话框与用户交互…不确定)

  • When user switches away from the app (e.g., with Alt-Tab), then goes back, the caret is gone and she is unable to type at all. A physical mouse click into the WebBrowser's window client area is required to get back the caret and keystrokes. This is because the control itself has received the focus. Another consideration is to add code to handle the GotFocus event and to then "change" where the focus goes. Tricky part is figuring out if this was "from" the document -> browser control or your app -> browser control. I can think of a few hacky ways to do this (variable reference based on losing focus event checked on gotfocus for example) but nothing that screams elegant.

    当用户离开应用程序时(例如,使用Alt-Tab),然后返回,插入符号就消失了,她根本无法输入。一个物理鼠标点击浏览器的窗口客户区,需要返回插入符号和击键。这是因为控制本身受到了关注。另一个考虑是添加代码来处理GotFocus事件,然后在焦点所在的位置进行“更改”。棘手的部分是搞清楚这是“从”文档->浏览器控件还是你的应用->浏览器控件。我可以想出一些简单易行的方法来实现这一点(例如,在gotfocus上检查焦点事件时,基于丢失焦点事件的变量引用),但是没有什么是优雅的。

  • Inconsistently, a dotted focus rectangle shows up around WebBrowser (when tabbing, but not when clicking). I could not find a way to get rid of it (FocusVisual does not help). I wonder if changing Focusable would help or hinder. Never tried it but I'm going to venture a guess that if it did work it would stop it from being keyboard navigable at all.

    不一致的是,在WebBrowser周围会出现一个虚线焦点矩形(在制表时显示,但在单击时不显示)。我找不到摆脱它的方法(FocusVisual没有帮助)。我想知道改变焦距是有益的还是有害的。我从来没有尝试过,但我敢打赌,如果它真的成功了,它就会阻止它成为键盘通航器。

  • Internally, WebBrowser never receives the focus. That's true for both logical focus (FocusManager) and input focus (Keyboard). The Keyboard.GotKeyboardFocusEvent and FocusManager.GotFocusEvent events never get fired for WebBrowser (although they both do for buttons in the same focus scope). Even when the caret is inside WebBrowser, FocusManager.GetFocusedElement(mainWindow) points to a previously focused element (a button) and Keyboard.FocusedElement is null. At the same time, ((IKeyboardInputSink)this.webBrowser).HasFocusWithin() returns true. People have hit issues with where 2 browser controls both show the focus(well... the caret) or even had a hidden control take the focus.

    在内部,WebBrowser不会收到焦点。对于逻辑焦点(FocusManager)和输入焦点(键盘)都是如此。键盘。GotKeyboardFocusEvent FocusManager。GotFocusEvent事件不会因为WebBrowser而被触发(尽管它们都在同一个焦点范围内对按钮进行操作)。即使插入符号在WebBrowser中,FocusManager.GetFocusedElement(mainWindow)也指向一个先前聚焦的元素(一个按钮)和键盘。FocusedElement是null。同时,(ikeyboarputsink)this.webBrowser . hasfocuswithin()返回true。人们遇到了两个浏览器控件同时显示焦点的问题。甚至有一个隐藏的控件来控制焦点。

All in all it's pretty awesome what you can do with the component but it's just the right mix of letting you control/change the behavior along with predefined sets of behavior to be maddening.

总之,你可以用这个组件做的非常棒,但是它只是让你控制/改变行为和预定义的行为集合的正确组合。

My suggestion would be to try to subclass the messages so you can direct the focus control directly through code and bypass it's window from trying to do so.

我的建议是尝试对消息进行子类化,这样您就可以通过代码直接指导焦点控件,并绕过它的窗口。

#2


3  

For anyone else stumbling upon this post and needing to set keyboard focus to the browser control (not a particular element within the control, necessarily), this bit of code worked for me.

对于任何偶然发现本文并需要将键盘焦点设置为浏览器控件(不一定是控件中的特定元素)的人来说,这段代码对我很有用。

First, add a project reference (under Extensions in VS) for Microsoft.mshtml.

首先,为Microsoft.mshtml添加一个项目引用(在VS中扩展)。

Next, whenever you'd like to focus the browser control (say for example, when the Window loads), simply "focus" the HTML document:

接下来,每当您想要对浏览器控件进行焦点(例如,当窗口加载时)时,只需对HTML文档进行“焦点”:

// Constructor
public MyWindow()
{
    Loaded += (_, __) =>
    {
        ((HTMLDocument) Browser.Document).focus();
    };
}

This will place keyboard focus inside the web browser control, and inside the "invisible" ActiveX window, allowing keys like PgUp / PgDown to work on the HTML page.

这将把键盘焦点放在web浏览器控件和“不可见的”ActiveX窗口中,允许像PgUp / PgDown这样的键在HTML页面上工作。

If you want to, you might be able to use DOM selection to find a particular element on the page, and try to focus() that particular element. I have not tried this myself.

如果需要,您可以使用DOM selection在页面上找到一个特定的元素,并尝试将这个特定的元素集中在()上。我自己还没试过。


推荐阅读
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • HTML5网页模板怎么加百度统计?
    本文介绍了如何在HTML5网页模板中加入百度统计,并对模板文件、css样式表、js插件库等内容进行了说明。同时还解答了关于HTML5网页模板的使用方法、表单提交、域名和空间的问题,并介绍了如何使用Visual Studio 2010创建HTML5模板。此外,还提到了使用Jquery编写美好的HTML5前端框架模板的方法,以及制作企业HTML5网站模板和支持HTML5的CMS。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
author-avatar
W14154988
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有