WPF WebBrowser control doesn't enter design mo

2019-03-30 09:56发布

问题:

I have a frustrating problem. Here's a simplified version of what I'm doing:

A UserControl in c# contains a toolbar and an embedded WebBrowser object. The toolbar contains an "Edit" button, which when clicked sets the webbrowser control in design mode. Another button, "Cancel", turns off design mode.

Pseudocode (very simplified):

public void SetDesignMode(bool dm) {
  IHTMLDocument2 doc = webBrowser.Document as IHTMLDocument2;
  if (dm) doc.designMode = "On";
  else doc.designMode = "Off";
  _designMode = dm;
  ReloadDocument(); // setting designmode clears the document element, so it must be reloaded
}

public void OnLoadCompleted() {
  IHTMLDocument2 doc = webBrowser.Document as IHTMLDocument2;
  if (!_documentLoaded) {
    if (_designMode) doc.designMode = "On";
    else doc.designMode = "Off";
    ReloadDocument();
    _documentLoaded = true;
  }
}

public void ReloadDocument() {
  _documentLoaded = false;
  // code that navigates to the document
}

The problem: If I click on the displayed web page, and then on the "Edit" button, the WebBrowser control will not become editable. The mouse pointer when hoovering over pictures/links show the web browser navigation mouse pointers, not the editing ones. If I click in the text, the caret won't display.

Debugging reveals that the designMode property on the document is actually set to "On" in this situation, but the control is behaving as if it is set to "Off".

If I don't click in the web page before clicking the "Edit" button, everything works as expected.

Elaboration: If I click the "Cancel" button when the control is in design mode, I get the corresponding (mis)behaviour, if the document have been clicked in.

Simply clicking on "Edit", then "Cancel", then "Edit" etc. without ever clicking in the document works fine (the mouseover test shows the proper mouse pointers, and I get link navigation or editing depending on the design mode if I click a link in the displayed document).

I've tried various techniques to make sure that another control gets focus before I change the designMode property, but it doesn't make any difference. I've searched MSDN and half of the known internet and haven't found any mention of this kind of problem. Flipping the designMode property like this seems to be quite unusal.

One more tidbit of information: I'm setting up document events by advising the document with a sink implemented by the usercontrol. I doubt that this should have any bearing on the problem, but I've included it here for the sake of being complete. Update: Disabling this doesn't change anything regarding the problem.

Does anybody recognize this problem?

Update: I've worked around the problem by re-creating the web browser control in SetDesignMode(). It's an ugly solution, but it works and does actually look ok. I'm very interested in any feedback on this problem, though. I believe it is a bug in MSHTML.

回答1:

I'm not quite sure if we had exactly the same problem, but I suppose my solution should work for you as well.

The basic issue seems to be that x64 reset the designMode attribute, as noted in this article. In my case, I set it to "On" after instantiating the webbrowser, but in the DocumentCompleted event, it was "Inherit" again. Setting it back to "On" in DocumentCompleted makes it editable, but clears the document. Setting the DocumentText again restarts the whole doom loop.

So one solution I found was to refrain from setting the DocumentText, instead I created an empty document, then set the body's (which at this point is no longer null) InnerHtml property:

doc.designMode = "On"; // enable editing

// designMode change resets the document, create it anew
webBrowser1.Document.Write("<html><body></body></html>")
webBrowser1.Document.Body.InnerHtml = "myDocumentText"

Obviously, this works only if you have the text ready, and not if you're navigating to an URL. However, there is another solution which worked for me, which seems easier and safer. I found it in this answer by LaughingJohn. I guess the first line depends on your application, you had the IHTMLDocument directly in webBrowser1.Document.

doc = webBrowser1.Document.DomDocument as IHTMLDocument2;
if (doc != null && doc.body != null)
    ((HtmlBody)doc.body).contentEditable = "true";


回答2:

It sounds to me like the WebBrowser gets the focus when you click on it and somehow holds on to it. Try this: click on the WebBrowser, then press the Tab key on the keyboard (which should move the focus off the WebBrowser) and then see if you can click on your buttons.

If you can, then try attaching a handler to the Button.MouseEnter event and call ((Button)sender).Foucs() in it to focus the button programmatically.