wpf - WebBrowser control keyboard and focus behavior -


apparently, there serious keyboard , focus issues wpf webbrowser control. i've put trivial wpf app, webbrowser , 2 buttons. app loads basic editable html markup (<body contenteditable='true'>some text</body>) , demonstrates following:

  • tabbing misbehaving. user needs hit tab twice see caret (text cursor) inside webbrowser , able type.

  • when user switches away app (e.g., alt-tab), goes back, caret gone , unable type @ all. physical mouse click webbrowser's window client area required caret , keystrokes.

  • inconsistently, dotted focus rectangle shows around webbrowser (when tabbing, not when clicking). not find way rid of (focusvisualstyle="{x:null}" not help).

  • internally, webbrowser never receives focus. that's true both logical focus (focusmanager) , input focus (keyboard). keyboard.gotkeyboardfocusevent , focusmanager.gotfocusevent events never fired webbrowser (although both buttons in same focus scope). when caret inside webbrowser, focusmanager.getfocusedelement(mainwindow) points focused element (a button) , keyboard.focusedelement null. @ same time, ((ikeyboardinputsink)this.webbrowser).hasfocuswithin() returns true.

i'd say, such behaviour dysfunctional true, that's how works. come hacks fix , bring in row native wpf controls textbox. still hope, maybe i'm missing obscure yet simple here. has dealt similar problem? suggestions on how fix appreciated.

at point, i'm inclined develop in-house wpf wrapper webbrowser activex control, based upon hwndhost. considering other alternatives webbrowser, such chromium embedded framework (cef).

the vs2012 project can downloaded here in case wants play it.

this xaml:

<window x:class="wpfwebbrowsertest.mainwindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         title="mainwindow" width="640" height="480" background="lightgray">      <stackpanel margin="20,20,20,20">         <togglebutton name="btnload" focusable="true" istabstop="true" content="load" click="btnload_click" width="100"/>          <webbrowser name="webbrowser" focusable="true" keyboardnavigation.istabstop="true" focusvisualstyle="{x:null}" height="300"/>          <button name="btnclose" focusable="true" istabstop="true" content="close" click="btnclose_click" width="100"/>     </stackpanel>  </window> 

this c# code, has bunch of diagnostic traces show how focus/keyboard events routed , focus is:

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 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 browser             this.webbrowser.navigatetostring("<body contenteditable='true' onload='focus()'>line 1<br>line 3<br>line 3<br></body>");             this.btnload.ischecked = true;         }          private void btnclose_click(object sender, routedeventargs e)         {             // close 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 , 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] situation doesn't better if host winforms webbrowser (in place of, or side-by-side wpf webbrowser):

<stackpanel margin="20,20,20,20">     <togglebutton name="btnload" focusable="true" istabstop="true" content="load" click="btnload_click" width="100"/>      <webbrowser name="webbrowser" focusable="true" keyboardnavigation.istabstop="true" focusvisualstyle="{x:null}" height="150" margin="10,10,10,10"/>      <windowsformshost name="wfhost" focusable="true" height="150" margin="10,10,10,10">         <wf:webbrowser x:name="wfwebbrowser" />     </windowsformshost>      <button name="btnclose" focusable="true" istabstop="true" content="close" click="btnclose_click" width="100"/> </stackpanel> 

the improvement see focus events on windowsformshost.

[update] extreme case: 2 webbrowser controls 2 carets showing @ same time:

<stackpanel margin="20,20,20,20">     <togglebutton name="btnload" focusable="true" istabstop="true" content="load" click="btnload_click" width="100"/>      <webbrowser name="webbrowser" focusable="true" keyboardnavigation.istabstop="true" focusvisualstyle="{x:null}" height="150" margin="10,10,10,10"/>     <webbrowser name="webbrowser2" focusable="true" keyboardnavigation.istabstop="true" focusvisualstyle="{x:null}" height="150" margin="10,10,10,10"/>      <button name="btnclose" focusable="true" istabstop="true" content="close" click="btnclose_click" width="100"/> </stackpanel>  this.webbrowser.navigatetostring("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text</textarea></body>"); this.webbrowser2.navigatetostring("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text2</textarea></body>"); 

this illustrates focus handling issue not specific contenteditable=true content.

the reason behaves way related fact it's activex control windows class (it handles mouse , keyboard interaction). in fact of time see component used you'll find main component taking full window because of this. doesn't have done way presents issues.

here's forum discussing exact same issue , it's causes can clarified reading last commentators article links:

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

to outline issues you're having

  • tabbing misbehaving. user needs hit tab twice see caret (text cursor) inside webbrowser , able type.

    that's because browser control window can tabbed to. doesn't "forward" tab it's child elements immediately.

    one way change handle wm message component keep in mind doing gets tricky when want "child" document inside of able handle messages.

    see: prevent webbrowser control stealing focus? "answer". although answer doesn't account can control whether component interacts through dialogs user setting silent property (may or may not exist in wpf control... not sure)

  • when user switches away app (e.g., alt-tab), goes back, caret gone , unable type @ all. physical mouse click webbrowser's window client area required caret , keystrokes. because control has received focus. consideration add code handle gotfocus event , "change" focus goes. tricky part figuring out if "from" document -> browser control or app -> browser control. can think of few hacky ways (variable reference based on losing focus event checked on gotfocus example) nothing screams elegant.

  • inconsistently, dotted focus rectangle shows around webbrowser (when tabbing, not when clicking). not find way rid of (focusvisualstyle="{x:null}" not help). wonder if changing focusable or hinder. never tried i'm going venture guess if did work stop being keyboard navigable @ all.

  • internally, webbrowser never receives focus. that's true both logical focus (focusmanager) , input focus (keyboard). keyboard.gotkeyboardfocusevent , focusmanager.gotfocusevent events never fired webbrowser (although both buttons in same focus scope). when caret inside webbrowser, focusmanager.getfocusedelement(mainwindow) points focused element (a button) , keyboard.focusedelement null. @ same time, ((ikeyboardinputsink)this.webbrowser).hasfocuswithin() returns true. people have hit issues 2 browser controls both show focus(well... caret) or had hidden control take focus.

all in it's pretty awesome can component it's right mix of letting control/change behavior along predefined sets of behavior maddening.

my suggestion try subclass messages can direct focus control directly through code , bypass it's window trying so.


Comments

Popular posts from this blog

c# - Send Image in Json : 400 Bad request -

jquery - Fancybox - apply a function to several elements -

An easy way to program an Android keyboard layout app -