【问题标题】:Adding Google Maps to a VB 2010 application将 Google 地图添加到 VB 2010 应用程序
【发布时间】:2012-02-26 09:27:13
【问题描述】:

我想在 VB 2010 中编写一个 Windows 窗体应用程序,允许用户在 Google 地图上搜索和查看地址或坐标点。我已经通过使用 WebBrowser 项目完成了这项工作。但是我想使用一个包装器,这样我就可以向用户显示地图,但仍然可以移动和缩放地图或给出方向等。我知道在开发 ASP.NET 站点时有办法做到这一点,但我想为 WindowsForms 应用程序执行此操作。有人可以帮忙吗?

【问题讨论】:

标签: vb.net winforms google-maps


【解决方案1】:

可能为时已晚,但我最近不得不在 vb 中处理谷歌地图,并想分享我的解决方案:

这个例子的第一部分解释了如何实现它。在第二个中,我将解释它是如何工作的。这试图成为一个普遍的例子。地图模板(参见第 3 步)和示例函数是完全可定制的。

################################ 实施########## ##################

步骤 1. 首先,创建一个新项目并选择 Windows 窗体应用程序。让我们将其名称保留为“Form1”。

第 2 步。 将 WebBrowser 控件(将保存您的地图)添加到您的 Form1。我们称之为“wbmap”

第 3 步。使用您喜欢的文本编辑器创建一个名为“googlemap_template.html”的 .html 文件并粘贴以下代码:

googlemap_template.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
     <style type="text/css">
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #gmap {
        height: 100%;
      }
     </style>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript">
        function initialize() {
            //Use window.X instead of var X to make a variable globally available 
            window.markers = new Array();
            window.marker_data = [[MARKER_DATA]];
            window.gmap = new google.maps.Map(document.getElementById('gmap'), {
            zoom: 15,
            center: new google.maps.LatLng(marker_data[0][0], marker_data[0][1]),
            mapTypeId: google.maps.MapTypeId.ROADMAP
          });
          var infowindow = new google.maps.InfoWindow();
          var newmarker, i;
          for (i = 0; i < marker_data.length; i++) {
              if (marker_data[0].length == 2) {
                  newmarker = new google.maps.Marker({
                      position: new google.maps.LatLng(marker_data[i][0], marker_data[i][1]),
                      map: gmap
                  });
              } else if (marker_data[0].length == 3) {
                  newmarker = new google.maps.Marker({
                      position: new google.maps.LatLng(marker_data[i][0], marker_data[i][1]),
                      map: gmap,
                      title: (marker_data[i][2])
                  });
              } else {
                  newmarker = new google.maps.Marker({
                      position: new google.maps.LatLng(marker_data[i][0], marker_data[i][1]),
                      map: gmap,
                      title: (marker_data[i][2]),
                      icon: (marker_data[i][3])
                  });
              }
            google.maps.event.addListener(newmarker, 'click', (function (newmarker, i) {
                return function () {
                    if (newmarker.title) {
                        infowindow.setContent(newmarker.title);
                        infowindow.open(gmap, newmarker);
                    }
                    gmap.setCenter(newmarker.getPosition());
                    // Calling functions written in the WF
                    window.external.showVbHelloWorld();
                    window.external.getMarkerDataFromJavascript(newmarker.title,i);
                }
            })(newmarker, i));
            markers[i] = newmarker;
          }
        }
        google.maps.event.addDomListener(window, 'load', initialize);
    </script>
    <script type="text/javascript">
        // Function triggered from the WF with no arguments
        function showJavascriptHelloWorld() {
            alert("Hello world in HTML from WF");
        }
     </script>
      <script type="text/javascript">
        // Function triggered from the WF with a String argument
        function focusMarkerFromIdx(idx) {
            google.maps.event.trigger(markers[idx], 'click');
        }
      </script>
  </head>
  <body>
    <div id="gmap"></div>
  </body>
</html>

这将作为我们的地图模板。我稍后会解释它是如何工作的。

第 4 步。 将 googlemap_template.hmtl 文件添加到您的项目(右键单击您的项目->添加->现有项目)

第 5 步。一旦它出现在您的解决方案资源管理器中,请将其属性设置为: - 构建操作 -> 嵌入式资源 - 自定义工具命名空间 -> 编写 项目名称

第 6 步。 添加一个新类(右键单击您的项目->添加->类)。在我的示例中,我将其称为 GoogleMapHelper。

第 7 步。 将以下代码粘贴到您的类中:

GoogleMapHelper.vb

    Imports System.IO
    Imports System.Reflection
    Imports System.Text

    Public Class GoogleMapHelper

    ' 1- googlemap_template.html must be copied in the main project folder
    ' 2- add the file into the Visual Studio Solution Explorer (add existing file)
    ' 3- set the properties of the file to: 
    '                                   Build Action -> Embedded Resource
    '                                   Custom Tool Namespace -> write the name of the project

    Private Const ICON_FOLDER As String = "marker_icons/" 'images must be stored in a folder inside  Debug/Release folder
    Private Const MAP_TEMPLATE As String = "WindowsApplication1.googlemap_template.html"
    Private Const TEXT_TO_REPLACE_MARKER_DATA As String = "[[MARKER_DATA]]"
    Private Const TMP_NAME As String = "tmp_map.html"


    Private mWebBrowser As WebBrowser

    'MARKER POSITIONS 
    Private mPositions As Double(,) 'lat, lon
    ' marker data allows different formats to include lat,long and optionally title and icon:
    ' op1: mMarkerData = New String(N-1, 1) {{lat1, lon1}, {lat2, lon2}, {latN, lonN}} 
    ' op2: mMarkerData = New String(N-1, 2) {{lat1, lon1,'title1'}, {lat2, lon2,'title2'}, {latN, lonN, 'titleN'}} 
    ' op3: mMarkerData = New String(N-1, 3) {{lat1, lon1,'title1','image1.png'}, {lat2, lon2,'title2','image2.png'}, {latN, lonN, 'titleN','imageN.png'}} 
    Private mMarkerData As String(,) = Nothing


    Public Sub New(ByRef wb As WebBrowser, pos As Double(,))
        mWebBrowser = wb
        mPositions = pos
        mMarkerData = getMarkerDataFromPositions(pos)
    End Sub

    Public Sub New(ByRef wb As WebBrowser, md As String(,))
        mWebBrowser = wb
        mMarkerData = md
    End Sub

    Public Sub loadMap()
        mWebBrowser.Navigate(getMapTemplate())
    End Sub

    Private Function getMapTemplate() As String

        If mMarkerData Is Nothing Or mMarkerData.GetLength(1) > 4 Then
            MessageBox.Show("Marker data has not the proper size. It must have 2, 3 o 4 columns")
            Return Nothing
        End If

        Dim htmlTemplate As New StringBuilder()
        Dim tmpFolder As String = Environment.GetEnvironmentVariable("TEMP")
        Dim dataSize As Integer = mMarkerData.GetLength(1) 'number of columns
        Dim mMarkerDataAsText As String = String.Empty
        Dim myresourcePath As String = My.Resources.ResourceManager.BaseName
        Dim myresourcefullPath As String = Path.GetFullPath(My.Resources.ResourceManager.BaseName)
        Dim localPath = myresourcefullPath.Replace(myresourcePath, "").Replace("\", "/") & ICON_FOLDER

        htmlTemplate.AppendLine(getStringFromResources(MAP_TEMPLATE))
        mMarkerDataAsText = "["

        For i As Integer = 0 To mMarkerData.GetLength(0) - 1
            If i <> 0 Then
                mMarkerDataAsText += ","
            End If
            If dataSize = 2 Then 'lat,lon
                mMarkerDataAsText += "[" & mMarkerData(i, 0) & "," + mMarkerData(i, 1) & "]"
            ElseIf dataSize = 3 Then 'lat,lon and title
                mMarkerDataAsText += "[" & mMarkerData(i, 0) & "," + mMarkerData(i, 1) & ",'" & mMarkerData(i, 2) & "']"
            ElseIf dataSize = 4 Then 'lat,lon,title and image
                mMarkerDataAsText += "[" & mMarkerData(i, 0) & "," + mMarkerData(i, 1) & ",'" & mMarkerData(i, 2) & "','" & localPath & mMarkerData(i, 3) & "']" 'Ojo a las comillas simples en las columnas 3 y 4 
            End If
        Next

        mMarkerDataAsText += "]"
        htmlTemplate.Replace(TEXT_TO_REPLACE_MARKER_DATA, mMarkerDataAsText)

        Dim tmpHtmlMapFile As String = (tmpFolder & Convert.ToString("\")) + TMP_NAME
        Dim existsMapFile As Boolean = False
        Try
            existsMapFile = createTxtFile(tmpHtmlMapFile, htmlTemplate)
        Catch ex As Exception
            MessageBox.Show("Error writing temporal file", "Writing Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
        End Try

        If existsMapFile Then
            Return tmpHtmlMapFile
        Else
            Return Nothing
        End If
    End Function

    Private Function getMarkerDataFromPositions(pos As Double(,)) As String(,)
        Dim md As String(,) = New String(pos.GetLength(0) - 1, 1) {}
        For i As Integer = 0 To pos.GetLength(0) - 1
            md(i, 0) = pos(i, 0).ToString("g", New System.Globalization.CultureInfo("en-US"))
            md(i, 1) = pos(i, 1).ToString("g", New System.Globalization.CultureInfo("en-US"))
        Next
        Return md
    End Function

    Private Function getStringFromResources(resourceName As String) As String
        Dim assem As Assembly = Me.[GetType]().Assembly

        Using stream As Stream = assem.GetManifestResourceStream(resourceName)
            Try
                Using reader As New StreamReader(stream)
                    Return reader.ReadToEnd()
                End Using
            Catch e As Exception
                Throw New Exception((Convert.ToString("Error de acceso al Recurso '") & resourceName) + "'" & vbCr & vbLf + e.ToString())
            End Try
        End Using
    End Function

    Private Function createTxtFile(mFile As String, content As StringBuilder) As Boolean
        Dim mPath As String = Path.GetDirectoryName(mFile)
        If Not Directory.Exists(mPath) Then
            Directory.CreateDirectory(mPath)
        End If
        If File.Exists(mFile) Then
            File.Delete(mFile)
        End If
        Dim sw As StreamWriter = File.CreateText(mFile)
        sw.Write(content.ToString())
        sw.Close()
        Return True
    End Function
    End Class

注意: MAP_TEMPLATE 常量必须包含您的项目名称

第 8 步。 现在我们可以使用 GoogleMapHelper 类将地图加载到我们的网络浏览器中,只需创建实例并调用它的 loadMap() 方法即可。如何构建 markerData 取决于您。在这个例子中,为了清楚起见,我是手写的。有 3 个选项来定义标记数据(请参阅 GoogleMapHelper 类 cmets)。请注意,如果您使用第三个选项(包括标题和图标),您必须在 Debug/Release 文件夹中创建一个名为“marker_icons”(或您在 GoogleMapHelper 常量 ICON_FOLDER 中定义的任何内容)的文件夹,并将您的 .png 文件放在那里。 就我而言:

我在 Form1 中创建了两个按钮来说明地图和 WF 如何交互。这是它的外观:

这里是代码:

Form1.vb

Imports System.IO
Imports System.Reflection
Imports System.Security.Permissions
Imports System.Text
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")>
<System.Runtime.InteropServices.ComVisible(True)>
Public Class Form1

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    Me.wbmap.ObjectForScripting = Me

    Dim onlyPositions As Double(,) = New Double(2, 1) {{42.13557, -0.40806}, {42.13684, -0.40884}, {42.13716, -0.40729}}
    Dim positonAndTitles As String(,) = New String(2, 2) {{"42.13557", "-0.40806", "marker0"}, {"42.13684", "-0.40884", "marker1"}, {"42.13716", "-0.40729", "marker2"}}
    Dim positonTitlesAndIcons As String(,) = New String(2, 3) {{"42.13557", "-0.40806", "marker0", "truck_red.png"}, {"42.13684", "-0.40884", "marker1", "truck_red.png"}, {"42.13716", "-0.40729", "marker2", "truck_red.png"}}

    'Dim gmh As GoogleMapHelper = New GoogleMapHelper(wbmap, onlyPositions)
    'Dim gmh As GoogleMapHelper = New GoogleMapHelper(wbmap, positonAndTitles)
    Dim gmh As GoogleMapHelper = New GoogleMapHelper(wbmap, positonTitlesAndIcons)
    gmh.loadMap()
End Sub

'############################### CALLING JAVASCRIPT METHODS ##############################
'This methods call methods written in googlemap_template.html
Private Sub callMapJavascript(sender As Object, e As EventArgs) Handles Button1.Click
    wbmap.Document.InvokeScript("showJavascriptHelloWorld")
End Sub

Private Sub callMapJavascriptWithArguments(sender As Object, e As EventArgs) Handles Button2.Click
    wbmap.Document.InvokeScript("focusMarkerFromIdx", New String() {2})
End Sub
'#########################################################################################

'############################### METHODS CALLED FROM JAVASCRIPT ##########################
'This methods are called by the javascript defined in googlemap_template.html when some events are triggered
Public Sub getMarkerDataFromJavascript(title As String, idx As String)
    MsgBox("Title: " & title & " idx: " & idx)
End Sub

Public Sub showVbHelloWorld()
    MsgBox("Hello world in WF from HTML")
End Sub
End Class

重要提示:不要忘记在您的 Form1 类定义之前添加这些行:

<PermissionSet(SecurityAction.Demand, Name:="FullTrust")>
<System.Runtime.InteropServices.ComVisible(True)>

他们所做的是告诉 .NET Framework 我们想要完全信任并使类对 COM 可见,因此 Form1 对 JavaScript 可见。

也不要在 Form1 加载函数中忘记这一点:

Me.wbmap.ObjectForScripting = Me

它将您的 Form1 类公开给 googlemap_template.hmtl 页面上的 JavaScript。

现在你可以执行了,它应该可以工作了

################################ 工作原理######## ########################

基本上,我们的 GoogleMapHelper 类所做的是读取我们的 googlemap_template.html,制作一个临时副本,替换与标记相关的代码 ([[MARKER_DATA]]) 并在我们表单的 Web 浏览器控件中执行页面。此 html 循环遍历所有标记并为每个标记分配一个“点击”侦听器。这个点击功能显然是完全可定制的。在示例中,如果标记有标题,它会打开一个信息窗口,将地图置于此类标记的中心,并调用在 Form1 类中定义的两个外部函数。

另一方面,我们可以在这个 html 中定义其他 javascript 函数(带或不带参数)以从我们的 Windows 窗体调用(通过使用 wbmap.Document.InvokeScript)。

【讨论】:

  • 这里有出色的工作。我即将进行一个类似的项目。希望我可以参考这个以获得指导。我需要一个界面(带菜单)和一个允许用户单击地图以创建路径(使用此 API)的显示:developers.google.com/maps/documentation/javascript/examples/…。然后我需要一种将他们的选择导出到 KML 文件的方法......应该是一个爆炸......:/
  • 很高兴你喜欢它!它确实应该指导你。我没有使用折线,但无论如何它们只是标记位置的列表,因此检索它们的纬度、经度坐标并在 WF 中调用函数来导出文件应该没有问题。祝你好运!
  • 您创建的这个很棒的项目是否有任何更新?例如支持其他事情,如标记点击、拖动等
  • 不幸的是,这段代码现在被嵌入到我不拥有的更广泛的代码中。不过,标记点击已经包含在内。并且拖动应该不难实现(只需在按住鼠标时用新的标记位置刷新地图)
【解决方案2】:

我用过这个控件,它真的很棒。它让你不仅可以使用 GoogleMaps,还可以使用几乎所有主要的地图服务,但是,我上次检查时,他们在使用 google 时遇到了一些许可问题。

GreatMaps on codeplex

【讨论】:

    【解决方案3】:

    Google Maps API for .NET 似乎正是您要找的东西

    http://gmaps.codeplex.com/

    来自网站

    该项目旨在提供 Google Maps API 中可用的所有功能。 它是用 C# 为 .NET Framework 3.5 开发的。

    虽然项目是 C# 语言,但您可能只需添加对该项目的引用并像使用任何其他引用一样使用它,并以任何符合 CLR 的语言编写代码,包括 VB。

    【讨论】:

      【解决方案4】:

      试试这个代码来获取两个位置之间的方向

      Dim queryaddress As New System.Text.StringBuilder
              Dim sStreet As String = String.Empty
              Dim sCity As String = String.Empty
              Dim sState As String = String.Empty
              Dim sPincode As String = String.Empty
              Dim sProvider_no As String = String.Empty
              queryaddress.Append("https://www.google.com/maps/dir/")
      
              If txtprovider_no.Text <> "" Then
                  sProvider_no = txtprovider_no.Text.Replace(" ", "+")
                  queryaddress.Append(sProvider_no + "," & "+")
              End If
              If txtState.Text <> "" Then
                  sState = txtState.Text.Replace("  ", "+")
                  queryaddress.Append(sState + "," & "+")
              End If
              If txtCity.Text <> "" Then
                  sCity = txtCity.Text.Replace("  ", "+")
                  queryaddress.Append(sCity + "," & "+")
              End If
              If txtPincode.Text <> "" Then
                  sPincode = txtPincode.Text.Replace("  ", "+")
                  queryaddress.Append(sPincode)
              End If
      
              queryaddress.Append("/")
              sStreet = String.Empty
              sCity = String.Empty
              sState = String.Empty
              sPincode = String.Empty
              If txtlindmark.Text <> "" Then
                  sStreet = txtlindmark.Text.Replace("  ", "+")
                  queryaddress.Append(sStreet + "," & "+")
              End If
              If txtclient_city.Text <> "" Then
                  sCity = txtclient_city.Text.Replace("  ", "+")
                  queryaddress.Append(sCity + "," & "+")
              End If
              If ttxtclient_city.Text <> "" Then
                  sPincode = ttxtclient_city.Text.Replace("  ", "+")
                  queryaddress.Append(sPincode)
              End If
              If txtclient_state.Text <> "" Then
                  sState = txtclient_state.Text.Replace("  ", "+")
                  queryaddress.Append(sState + "," & "+")
              End If
      
              WBR.Navigate(queryaddress.ToString())
      

      【讨论】:

        【解决方案5】:

        Google Maps Control 2017 项目将 Google Maps API 包装为 ASP.NET 自定义控件,提供了一种使用“零编写 JavaScript”代码在 ASP.NET C# 或 VB 页面中添加 Google 地图的简单快捷方式。

        ASP.NET Google Maps Control 包含许多功能(标记、折线、多边形、方向),并以令人愉悦的 ASP.NET 编码方式为您提供几乎所有 Google Maps API 功能。

        PM>Install-Package GoogleMapControl

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-10
          相关资源
          最近更新 更多