Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF WebBrowser control doesn't enter design mode when the document property is changed

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.

like image 911
Ludvig A. Norin Avatar asked Nov 19 '09 19:11

Ludvig A. Norin


1 Answers

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";
like image 59
Mike Fuchs Avatar answered Oct 26 '22 13:10

Mike Fuchs