<CharlieDigital/> Programming, Politics, and uhh…pineapples

8Jul/09Off

Leveraging The Windows Forms WebBrowser Control (For The Win)

Posted by Charles Chen

I've been working on a little utility to experiment with the XMPP protocol.  The idea was to write a tool that would allow me to send, receive, and display the XML stream and XML stanza messages at the core of XMPP.


Of course, I could have implemented it using a simple multi-line text box for the XML entry, but that would mean that I wouldn't have nice things like syntax highlighting (for XML) and nice (auto) indentation.


On the desktop, I'm not familiar with any free Windows Forms editor controls that are capable of syntax highlighting.  But on the web side, there are several free, open source script libraries at our disposal.  For example, CodePress, EditArea, and CodeMirror.


I chose CodeMirror for this application as it was the simplest library that met my needs.



There really aren't any tricks to this aside from getting the URL correct.  In this case, I have my static HTML content in a directory in my project:



And I set the content files to "Copy always" in the properties pane for the files so that they get copied to the output directory of the project.  To set the correct path, I find the executing directory of the application and set the URL properly:


protected override void OnLoad(EventArgs e)
{
if (!DesignMode)
{
string path = Path.Combine(
Environment.CurrentDirectory,
"HTML/input-page.html");
path = path.Replace('\\', '/');

_inputBrowser.Url = new Uri(path);
}

base.OnLoad(e);
}


Note that I check if the control is in design mode (the designer throws an error if you don't do this since the path points to Visual Studio's runtime directory instead of your applications output).  Now all that's left is to get the script and style references correct in your HTML page:


<script src="../HTML/CodeMirror/js/codemirror.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="../HTML/CodeMirror/css/docs.css" />

And in your script:


<script type="text/javascript">
var editor = CodeMirror.fromTextArea('code', {
height: "210px",
parserfile: "parsexml.js",
stylesheet: "../HTML/CodeMirror/css/xmlcolors.css",
path: "../HTML/CodeMirror/js/",
continuousScanning: 500,
lineNumbers: true,
textWrapping: false
});
</script>

The final part is getting your Windows forms code talking to the Javascript in the browser.  In this case, I've written some simple Javascript that interacts with the editor control:


<script type="text/javascript">
var $g = document.getElementById;

function resize(height) {
var textArea = $g("code");

// Get the iframe.
var editor = textArea.nextSibling.firstChild;

editor.style.height = (height - 1) + "px";
}

function reset() {
editor.setCode("");
}

function addContent(data) {
var code = editor.getCode();

editor.setCode(code + data);

editor.reindent();
}

function setContent(data) {
editor.setCode(data);

editor.reindent();

// Scroll to bottom.
editor.selectLines(editor.lastLine(), 0);
}

function getContents() {
return editor.getCode();
}
</script>


From the application code, we can call these script functions using the InvokeScript method:


private void AddStreamMessageInternal(string data)
{
if (_streamBrowser.Document != null)
{
// Get the contents
string code = (string) _streamBrowser.Document.InvokeScript(
"getContents", new object[] {});

code = code + data;

code = code.Replace("><", ">\r\n<");

_streamBrowser.Document.InvokeScript(
"setContent", new object[] {code});
}
}

private void AdjustSize()
{
// Call a resize method to change the HTML editor size.
if (_streamBrowser.Document != null)
{
_streamBrowser.Document.InvokeScript(
"resize", new object[] {_streamBrowser.ClientSize.Height});
}
}

public void RefreshBrowserContents()
{
if (_streamBrowser.Document != null)
{
_streamBrowser.Document.InvokeScript(
"reset", new object[] {});
}
}


Awesome! You can see that I can both pass arguments into the Javascript functions and read the return data from the Javascript function as well.  The big win is that now you can take advantage of your favorite Javascript utilities in your Windows Forms applications.

Filed under: .Net, Awesome No Comments