0

Bit of a doozy here. I've got various COM exposed systems and I've implemented Google maps (v3) into my .net software. What I'm trying to do now, is that when a user edits a polygon (defining an area), I send back all path points to .net for storing into our database.

My problem is that .Net knows that the JS array I pass back is X elements in size, but for the life of me I can't figure out how to reference the values while iterating through the array.

Here's the .NET (VB) method I'm using from JS with window.external

Public Sub AreaPointMoved(ByRef obj As Object, ByVal s As String)
    MsgBox(s)    ' contains a string of lat/lngs from JS
    MsgBox(obj.length)

    For i As Integer = 0 To obj.length
        MsgBox(obj(i).lat & ", " & obj(i).lng) ' this doesn't work
        'MsgBox(obj.lat & ", " & obj.lng) ' this doesn't work
    Next
End Sub

And the JS that's sending stuff back upon the set_at event being triggered:

    function DrawAreaOverlay(area, col)
    {
        var coordsString = "";
        var areaCoords = [];
        overlayLayer[overlayCount] = new Array();

        for(var j=0; j<area.Count; j++)
        {
            areaCoords.push(new google.maps.LatLng(area.Item(j).lng, area.Item(j).lat));
        }

        var poly = new google.maps.Polygon({
            paths: areaCoords,
            strokeColor: col,
            strokOpacity: 0.35,
            strokeWeight: 2,
            fillColor: col,
            fillOpacity: 0.25,
            geodesic: false,
            editable: canEdit,
            draggable: canDrag,
            map: map
        });

        overlayLayer[overlayCount].push(poly);

        poly.getPaths().forEach(function(path, index){
            google.maps.event.addListener(path, 'set_at', function(){
                var arrayOfPoints = new Array();
                var g = new Array();

                arrayOfPoints = poly.getPath();                         
                coordsString = "";

                for(var i=0; i<arrayOfPoints.length; i++)
                {                       
                    //simpleArray[i] = poly.getPath().getAt(i).lat() + ", " + poly.getPath().getAt(i).lng();
                    geoObj = new Object();
                    geoObj.lat = poly.getPath().getAt(i).lat();
                    geoObj.lng = poly.getPath().getAt(i).lng();

                    g.push(geoObj);

                    coordsString += poly.getPath().getAt(i).lat() + ", " + poly.getPath().getAt(i).lng() + "|";
                }

                window.external.AreaPointMoved(g, coordsString);
                //alert(path.getLength());
            });
        });
    }

I'm really confused. Getting objects from .net to JS was a doddle. But I can't for the life of me figure out what I'm doing wrong on the reverse :(

Cheers.

5
  • What if you put a breakpoint on the MsgBox and inspect whats in there? Commented Jan 28, 2014 at 12:42
  • Displays: System.__COMObject - But wont let me see any fields or properties of any kind. Commented Jan 28, 2014 at 12:46
  • Try using obj[i] instead of obj(i) Commented Jan 28, 2014 at 12:55
  • Doesn't even compile. "Identifier expected." using: obj[0].lat - I'll get around it with Strings. The old school way! I was just hoping that because it was simple getting an enumerable array across to JS, it'd be easy returning and iterating one from JS. Commented Jan 28, 2014 at 13:37
  • A similar q/a: stackoverflow.com/a/20943173/1768303. The code is in C#, but the same Reflection API can be used from VB.NET. Commented Jan 29, 2014 at 9:59

1 Answer 1

1

According to answer like this, you have two options at your disposal for interacting with non-primitive arguments with calls to your ObjectForScripting. This Connect thread says you should use a dynamic as the argument type.

To my surprise, I learned that VB.NET doesn't have a an equivalent to C#'s dynamic keyword. Apparently Option Strict Off and Option Infer On accomplish the same ends:

Option Strict Off
Option Infer On

Public Sub AreaPointMoved(ByRef obj As Object, ByVal s As String)
    For i As Integer = 0 To obj.length
        'late binding to .lat and .lng should work now
        ' open Debug > Windows > Immediate
        Debug.Print(obj(i).lat) 
        Debug.Print(obj(i).lng)
   Next
 End Sub

This is untested as I can't easily test any of this code. If this doesn't work, the second hail mary is using reflection to invoke the property:

Public Sub AreaPointMoved(ByRef obj As Object, ByVal s As String)
    Dim lat As Double
    Dim lng As Double


    For i As Integer = 0 To obj.length
        lat = obj(i).GetType().InvokeMember("lat", BindingFlags.InvokeMethod, Nothing, obj(i), Nothing)
        lng = obj(i).GetType().InvokeMember("lng", BindingFlags.InvokeMethod, Nothing, obj(i), Nothing)
        ' view in Debug > Windows > Immediate
        Debug.Print(lat) 
        Debug.Print(lng)
   Next
 End Sub

Forgive my VB.NET for any syntax errors. My skills translating C# to VB.NET are rusty at best.

Have you thought about using an array of arrays of doubles? You should not need an object property just to pass coordinates:

Public Sub AreaPointMoved(ByVal coordinates()() As Double)
End Sub
 for(var i=0; i<arrayOfPoints.length; i++)
 {                       
      g.push([poly.getPath().getAt(i).lat(),  poly.getPath().getAt(i).lng()]);
 }
 window.external.AreaPointMoved(g);

Hopefully one of these will help you sort this out. Good luck!


Sidebar: I highly recommend using Chromium Embedded Framework (CEF) or possibly Awesomium over the Windows WebBrowser control (which is a COM interop wrapper around Internet Explorer). Embedding Google Maps into a desktop app is going to be way smoother with a browser based on Chromium over IE. Both CEF and Awesomium have much richer ways to accomplish bi-directional calls between .Net IL and Javascript. You are having a hard time with the window.external and WebBrowser.ObjectForScripting simply because it is a crappy API for anything serious.

Sign up to request clarification or add additional context in comments.

1 Comment

Agreed that the IE browser wrapper isn't overly pleasant to use! But it's mainly a prototype at the moment. Thanks for the links, I'll take a look and see what I can do. Most of the grunt work is done within the JS itself, so hopefully it'll just be a case of migrating controls and a different way of loading the filesystem content. Cheers! +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.