2

I am creating an application that interfaces with Google's Maps API v3. My current approach is using a WebBrowser control by WebBrowser.Navigate("Map.html"). This is working correctly at the moment; however, I am also aware of WebBrowser.InvokeScript(). I have seen this used to execute a javascript function, but I would like to have something like the following structure:

APICalls.js - Contains different functions that can be called, or even separated out into a file for each function if necessary.

MapInterface.cs

WebBrowser.InvokeScript("APICalls.js", args) - Or control the javascript variables directly.

I have seen the InvokeScript method used, but none of the examples gave any detail to the source of the function, so I'm not sure if it was calling it from an html file or js file. Is it possible to have a structure like this, or a similarly organized structure, rather than creating an html file with javascript in each one and using Navigate()?

Additionally, are there any easier ways to use Google Maps with WPF. I checked around, but all of the resources I found were at least 2-3 years old, which I believe is older than the newest version of the maps API.

Daniel Underwood
  • 2,191
  • 2
  • 22
  • 48

1 Answers1

4

I can't suggest a better way of using Google Maps API with WPF (although I'm sure it exists), but I can try to answer the rest of the question.

  • First, make sure to enable FEATURE_BROWSER_EMULATION for your WebBrowser app, so Google Maps API recognizes is it as modern HTML5-capable browser.

  • Then, navigate to your "Map.html" page and let it finish loading. Here's how it can be done using async/await (the code is for the WinForms version of WebBrowser control, but the concept remains the same).

  • You can have your APICalls.js as a separate local file, but you'd need to create and populate a <script> element for it from C#. You do it once for the session.

Example:

var scriptText = File.ReadAllText("APICalls.js");
dynamic htmlDocument = webBrowser.Document;
var script = htmlDocument.createElement("script");
script.type = "text/javascript";
script.appendChild(htmlDocument.createTextNode(scriptText));
htmlDocument.body.appendChild(script);

For example, your JavaScript entry point function in APICalls.js may look like this:

(function() {
    window.callMeFromCsharp = function(arg1, arg2) {
        window.alert(arg1 + ", " +arg2);
    } 
})();

Which you could call from C# like this:

webBrowser.InvokeScript("callMeFromCsharp", "Hello", "World!");

[UPDATE] If you're looking for a bit more modular or object-oriented approach, you can utilize the dynamic feature of C#. Example:

JavaScript:

(function() {
    window.apiObject = function() {
        return {
            property: "I'm a property",
            Method1: function(arg) { alert("I'm method 1, " + arg); },
            Method2: function() { return "I'm method 2"; }
        };
    } 
})();

C#:

dynamic apiObject = webBrowser.InvokeScript("apiObject");
string property = apiObject.property;
MessageBox.Show(property);
apiObject.Method1("Hello!");
MessageBox.Show(apiObject.Method2());
Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • I've came up with a similar solution, but currently it's just executing from an `initialize` in the javascript as soon as it loads. I like the ability to call from C# much better though. As I understand it, `InvokeScript` is just called by function name once it is loaded in HTML? I didn't really see a clear explanation in the documentation for the call so I was confused. And thanks for the `FEATURE_BROWSER_EMULATION` tip. I was running into some issues with the Maps API not being able to do some HTML5 stuff. – Daniel Underwood Oct 25 '13 at 01:22
  • @danielu13, yes `InvokeScript` can invoke functions available in the page's global JavaScript namespace, including the ones explicitly available on the DOM `window` object. If your're looking for a more modular approach, I've updated the answer with an example. – noseratio Oct 25 '13 at 01:38
  • Hmmm. I'm getting `Unexpected call to method or property access.` on `script.appendChild(htmlDocument.createTextNode(scriptText));`. One weird thing I noticed is that `htmlDocument.body` and `htmlDocument.doctype` are both null, but are clearly in the html page. Any ideas? – Daniel Underwood Oct 25 '13 at 15:32
  • @danielu13, are you doing this upon [`WebBrowser.LoadCompleted`](http://msdn.microsoft.com/en-us/library/system.windows.controls.webbrowser.loadcompleted(v=vs.110).aspx)? Check `htmlDocument.readyState`, it should be `complete`. – noseratio Oct 25 '13 at 23:07