WPF使用GMap.net框架開發地圖應用

GMap.NET有兩個版本,分別是WinForm和WPF的版本,WinForm版本的教程很多。這次主要介紹的WPF版本的操作。

要下載GMap.NET請點擊這裏,這個最好下載下來,可以參考裏面的Demo來學習。下載下來後,用visual studio打開SourceCode裏面的sln文件。打開的時候可能需要讓你下載什麼東西,這個有點不記得了,但是關於數據庫的那個應該不用下載。

1、導入dll

1-1、第一種方法
按照下圖打開NuGet包管理器,然後輸入Gmap.net進行搜索,點擊想要安裝的dll,然後選擇項目,點擊安裝即可。
在這裏插入圖片描述
在這裏插入圖片描述
1-2、第二種方法
這種方法就是運行下載下來的源代碼,然後再拷貝Debug下面生成的dll文件。這樣的做法更加靈活,可以自己更改代碼。

2、導入GMapControl控件

2-1、再工具箱空白處右鍵“選項”然後選中GMapControl,點擊確定。即可在工具箱中使用GMapControl控件。
在這裏插入圖片描述

3、導入高德地圖

高德的地圖和google地圖使用的座標一致,可以切換使用,但是據說百度的又增加了偏移。
3-1、普通地圖

using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.Projections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace jiemian3.CustomMap
{
    public abstract class AMapProviderBase : GMapProvider
    {
        public AMapProviderBase()
        {
            MaxZoom = null;
            RefererUrl = "http://www.amap.com/";
            //Copyright = string.Format("©{0} 高德 Corporation, ©{0} NAVTEQ, ©{0} Image courtesy of NASA", DateTime.Today.Year);    
        }

        public override PureProjection Projection
        {
            get { return MercatorProjection.Instance; }
        }

        GMapProvider[] overlays;
        public override GMapProvider[] Overlays
        {
            get
            {
                if (overlays == null)
                {
                    overlays = new GMapProvider[] { this };
                }
                return overlays;
            }
        }
    }

    public class AMapProvider : AMapProviderBase
    {
        public static readonly AMapProvider Instance;

        readonly Guid id = new Guid("EF3DD303-3F74-4938-BF40-232D0595EE88");
        public override Guid Id
        {
            get { return id; }
        }

        readonly string name = "AMap";
        public override string Name
        {
            get
            {
                return name;
            }
        }

        static AMapProvider()
        {
            Instance = new AMapProvider();
        }

        public override PureImage GetTileImage(GPoint pos, int zoom)
        {
            try
            {
                string url = MakeTileImageUrl(pos, zoom, LanguageStr);
                return GetTileImageUsingHttp(url);
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        string MakeTileImageUrl(GPoint pos, int zoom, string language)
        {
            var num = (pos.X + pos.Y) % 4 + 1;
            //string url = string.Format(UrlFormat, num, pos.X, pos.Y, zoom);
            string url = string.Format(UrlFormat, pos.X, pos.Y, zoom);
            return url;
        }

        //static readonly string UrlFormat = "http://webrd04.is.autonavi.com/appmaptile?x={0}&y={1}&z={2}&lang=zh_cn&size=1&scale=1&style=7";
        static readonly string UrlFormat = "http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={0}&y={1}&z={2}";
    }
}

3-2、高德衛星地圖,但是高德衛星地圖(官網的地圖)的數據不完整

using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.Projections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace jiemian3.CustomMap
{
    public class AMapSateliteProvider : AMapProviderBase
    {
        private readonly Guid id = new Guid("FCA94AF4-3467-47c6-BDA2-6F52E4A145BC");
        public static readonly AMapSateliteProvider Instance = new AMapSateliteProvider();
        //private readonly string name = Resources.Strings.AMapSatellite;
        private readonly string name = "AMapSatellite";
        private static readonly string UrlFormat = "http://webst04.is.autonavi.com/appmaptile?x={0}&y={1}&z={2}&lang=zh_cn&size=1&scale=1&style=6";

        public override PureImage GetTileImage(GPoint pos, int zoom)
        {
            string url = this.MakeTileImageUrl(pos, zoom, GMapProvider.LanguageStr);
            return base.GetTileImageUsingHttp(url);
        }

        private string MakeTileImageUrl(GPoint pos, int zoom, string language)
        {
            string str = string.Format(UrlFormat, pos.X, pos.Y, zoom);
            Console.WriteLine("url:" + str);
            return str;
        }

        public override Guid Id
        {
            get
            {
                return this.id;
            }
        }

        public override string Name
        {
            get
            {
                return this.name;
            }
        }
    }
}
4、自定義Marker

winform版的自己GMap提供了第三方的marker,但是WPF的需要自己寫。可以參考源代碼項目中Demo目錄下面的“Demo.WindowsPresentation”,WPF所有的代碼都可以參考這個Demo。我直接把“Demo.WindowsPresentation”裏面對應的代碼粘貼到下面。

因爲這些代碼再一個單獨的文件夾下面,所以注意命名空間和路徑,自己做調整。
CustomMarkerRed.xaml

<UserControl
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="Demo.WindowsPresentation.CustomMarkers.CustomMarkerRed"
	Height="40" Width="30" Opacity="10">
		<Image Name="icon" Source="red-dot.png" VerticalAlignment="Center" HorizontalAlignment="Center" />
</UserControl>

CustomMarkerRed.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using GMap.NET.WindowsPresentation;

namespace Demo.WindowsPresentation.CustomMarkers
{
   /// <summary>
   /// Interaction logic for CustomMarkerDemo.xaml
   /// </summary>
   public partial class CustomMarkerRed
   {
      Popup Popup;
      Label Label;
      GMapMarker Marker;
      MainWindow MainWindow;

      public CustomMarkerRed(MainWindow window, GMapMarker marker, string title)
      {
         this.InitializeComponent();

         this.MainWindow = window;
         this.Marker = marker;

         Popup = new Popup();
         Label = new Label();

         this.Loaded += new RoutedEventHandler(CustomMarkerDemo_Loaded);
         this.SizeChanged += new SizeChangedEventHandler(CustomMarkerDemo_SizeChanged);
         this.MouseEnter += new MouseEventHandler(MarkerControl_MouseEnter);
         this.MouseLeave += new MouseEventHandler(MarkerControl_MouseLeave);
         this.MouseMove += new MouseEventHandler(CustomMarkerDemo_MouseMove);
         this.MouseLeftButtonUp += new MouseButtonEventHandler(CustomMarkerDemo_MouseLeftButtonUp);
         this.MouseLeftButtonDown += new MouseButtonEventHandler(CustomMarkerDemo_MouseLeftButtonDown);

         Popup.Placement = PlacementMode.Mouse;
         {
            Label.Background = Brushes.Blue;
            Label.Foreground = Brushes.White;
            Label.BorderBrush = Brushes.WhiteSmoke;
            Label.BorderThickness = new Thickness(2);
            Label.Padding = new Thickness(5);
            Label.FontSize = 22;
            Label.Content = title;
         }
         Popup.Child = Label;
      }

      void CustomMarkerDemo_Loaded(object sender, RoutedEventArgs e)
      {
         if(icon.Source.CanFreeze)
         {
            icon.Source.Freeze();
         }
      }

      void CustomMarkerDemo_SizeChanged(object sender, SizeChangedEventArgs e)
      {
         Marker.Offset = new Point(-e.NewSize.Width/2, -e.NewSize.Height);
      }

      void CustomMarkerDemo_MouseMove(object sender, MouseEventArgs e)
      {
         if(e.LeftButton == MouseButtonState.Pressed && IsMouseCaptured)
         {
            Point p = e.GetPosition(MainWindow.MainMap);
            Marker.Position = MainWindow.MainMap.FromLocalToLatLng((int) p.X, (int) p.Y);
         }
      }

      void CustomMarkerDemo_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
      {
         if(!IsMouseCaptured)
         {
            Mouse.Capture(this);
         }
      }

      void CustomMarkerDemo_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
      {
         if(IsMouseCaptured)
         {
            Mouse.Capture(null);
         }
      }

      void MarkerControl_MouseLeave(object sender, MouseEventArgs e)
      {
         Marker.ZIndex -= 10000;
         Popup.IsOpen = false;
      }

      void MarkerControl_MouseEnter(object sender, MouseEventArgs e)
      {
         Marker.ZIndex += 10000;
         Popup.IsOpen = true;
      }
   }
}

在主界面中使用

currentMarker = new GMapMarker(MainMap.Position);
{
   currentMarker.Shape = new CustomMarkerRed(this, currentMarker, "custom position marker");
   currentMarker.Offset = new System.Windows.Point(-15, -15);
   currentMarker.ZIndex = int.MaxValue;
   MainMap.Markers.Add(currentMarker);
}

圖片如下:
標記

5、繪製多邊形

下面只公佈部分代碼和思想,如果有不懂的可以提問。有些不方面提供。
5-1、多邊形
使用dll中提供的GMapPolygon類。

List<PointLatLng> points = new List<PointLatLng>();
//在這塊添加一些points
GMapPolygon polygon = new GMapPolygon(points);

polygon.ZIndex = 10; //設置Zindex,顯示的優先級(層)
polygon.RegenerateShape(gmap); //gmap就是地圖控件
//下面這個比較重要,是設置樣式。
(polygon.Shape as Path).Stroke = Brushes.GreenYellow;
(polygon.Shape as Path).StrokeThickness = 5;
(polygon.Shape as Path).Effect = null;
gmap.Markers.Add(polygon);

5-2、折線(路徑)
使用GMapRoute類,基本和上面的一樣。

List<PointLatLng> points = new List<PointLatLng>();
//在這塊添加一些points
GMapRoute route = new GMapRoute(points);//
route.ZIndex = 10;
route.RegenerateShape(gmap);
(route.Shape as Path).Stroke = Brushes.Blue;
(route.Shape as Path).StrokeThickness = 5;
(route.Shape as Path).Effect = null;
gmap.Markers.Add(route);

5-3、根據鼠標畫矩形
這個需要自己寫一些鼠標事件。這個自己發揮吧,代碼有點亂,自己思考也不難。因爲一些原因,這部分代碼不能全部公佈,多多理解。
下面的代碼是畫矩形的,只是沒有鼠標事件的代碼。已經很接近了。

PointLatLng startpoint = mainmarker.Position;
      List<PointLatLng> list_points = new List<PointLatLng>();
     
      if (startpoint.Lat > current_point.Lat)
      {
          if (startpoint.Lng < current_point.Lng)
          {
              //右下
              list_points.Add(startpoint);
              list_points.Add(new PointLatLng(startpoint.Lat, current_point.Lng));
              list_points.Add(current_point);
              list_points.Add(new PointLatLng(current_point.Lat, startpoint.Lng));
          }
          else
          {
              //左下
              list_points.Add(startpoint);
              list_points.Add(new PointLatLng(current_point.Lat, startpoint.Lng));
              list_points.Add(current_point);
              list_points.Add(new PointLatLng(startpoint.Lat, current_point.Lng));
          }
      }
      else
      {
          if (startpoint.Lng < current_point.Lng)
          {
              //右上
              list_points.Add(startpoint);
              list_points.Add(new PointLatLng(startpoint.Lat, current_point.Lng));
              list_points.Add(current_point);
              list_points.Add(new PointLatLng(current_point.Lat, startpoint.Lng));
          }
          else
          {
              //左上
              list_points.Add(startpoint);
              list_points.Add(new PointLatLng(current_point.Lat, startpoint.Lng));
              list_points.Add(current_point);
              list_points.Add(new PointLatLng(startpoint.Lat, current_point.Lng));
          }
      }
      double lat = (startpoint.Lat+current_point.Lat) / 2;
      double lng = (startpoint.Lng + current_point.Lng) / 2;
      double heightlat = Math.Abs(current_point.Lat-startpoint.Lat);
      double widthlng = Math.Abs(current_point.Lng-startpoint.Lng);
      rectLatLng = RectLatLng.FromLTRB(startpoint.Lng,startpoint.Lat,current_point.Lng,current_point.Lat);

      rectangle = new GMapPolygon(list_points);
      rectangle.ZIndex = Rectangle_index;
      rectangle.RegenerateShape(gmap);
      (rectangle.Shape as Path).Stroke = Brushes.GreenYellow;
      (rectangle.Shape as Path).StrokeThickness = 5;
      (rectangle.Shape as Path).Effect = null;

      gmap.Markers.Add(rectangle);

5-4、根據鼠標畫圓形
上面的矩形還好是GMAP自己控件畫的,但是圓形沒有,也不能根據點畫,因爲有無數個點。最主要的是畫的圓形要能夠更具地圖縮放。這部分還是參考Demo中的代碼。思路是:使用一個XMAL控件,裏面是一個圓,設置屬性是填充的,然後改變邊框即可改變圓的大小。首先根據鼠標移動位置和中心點的經緯度座標轉化成界面座標,然後計算半徑,畫圓。
Circle.xaml

<UserControl x:Class="Demo.WindowsPresentation.CustomMarkers.Circle"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300" Background="Transparent">
    <Grid>
        <Ellipse Stroke="Red" Fill="AliceBlue" Opacity="0.44" />
    </Grid>
</UserControl>

Circle.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using GMap.NET;

namespace Demo.WindowsPresentation.CustomMarkers
{
   /// <summary>
   /// Interaction logic for Circle.xaml
   /// </summary>
   public partial class Circle : UserControl
   {
      public Circle()
      {
         InitializeComponent();
      }

      public PointLatLng Center;
      public PointLatLng Bound;
   }
}

畫圓的代碼

PointLatLng center = mainmarker.Position;
circle = new GMapMarker(center);
circle_shape = new Circle();
circle_shape.Center = center;
circle_shape.Bound = current_point;
circle_shape.Tag = circle;
circle_shape.IsHitTestVisible = false;
UpdateCircle(circle_shape);//下面的代碼
circle.Shape = circle_shape;
circle.ZIndex = Circle_index;
gmap.Markers.Add(circle);

更新圓的大小的代碼,這塊每次在地圖加載的時候調用就可以讓圓不斷變化大小。

 private void UpdateCircle(Circle c)
 {
     var pxCenter = gmap.FromLatLngToLocal(c.Center);
     var pxBounds = gmap.FromLatLngToLocal(c.Bound);
     Console.WriteLine(pxCenter + "            " + pxBounds);
     double a = (double)(pxBounds.X - pxCenter.X);
     double b = (double)(pxBounds.Y - pxCenter.Y);
     //半徑
     var pxCircleRadius = Math.Sqrt(a * a + b * b);
     Console.WriteLine("半徑爲:" + pxCircleRadius);
     c.Width = pxCircleRadius * 2;
     c.Height = pxCircleRadius * 2;
     (c.Tag as GMapMarker).Offset = new System.Windows.Point(-c.Width / 2, -c.Height / 2);
 }
6、Zindex

WPF中沒有GMapOverlay,但是可以使用Zindex來設置虛擬的。Zindex越大的顯示就越靠上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章