使用 GMap.NET 實現新增標註、移動標註功能。(WPF版,附原始碼)
前言
在WPF嵌入地圖,有兩種方式: 瀏覽器方式;控制元件方式。
1)瀏覽器方式就是使用瀏覽器控制元件WebBrowser,設定好網址就行了。這種方式與地圖的互動不太直接,需要懂html、javascript。對於不懂web程式設計的開發者來說,有點困難。
2)控制元件方式就是使用第三方控制元件;不需要處瞭解web相關知識,使用起來比較直接,易於理解。GMap.net 類庫就實現了這種控制元件。
GMap.net 簡介
GMap.NET 是一個強大、免費、跨平臺、開源的.NET控制元件,它在Windows Forms 和WPF環境中能夠通過Google, Yahoo!, Bing, OpenStreetMap, GIS/">ArcGIS, Pergo, SigPac等實現尋找路徑、地理編碼以及地圖展示功能,並支援快取和執行在Mobile環境中。
GMap.NET多年前已經存在,最初主要支援WinForm。WPF出現的較晚;但是,現在這個控制元件也可用於WPF開發。不過,網上相關WPF開發的例子較少。因為工作需要,最近使用這個控制元件開發了gis相關專案,把開發過程中的使用技巧寫出來,以供參考!
其中部分程式碼參考了別人的文章,稍作修改!
程式介面:
將GMap.net加入專案
使用NuGet,搜尋GMap.net就可以找到該控制元件:
新增地圖
GMap.net是國外開發的,不過也能很好的支援國內地圖。這個控制元件是開放的,只要按照要求完成相關設定,就可以把各類地圖加進來。
要理解這些設定,就需要先理解地圖的基本知識。我在這裡就不多述。簡單一句話句話就是:地圖其實就多個圖片拼接而來的;你需要告訴控制元件,如何根據地理座標和縮放級別獲取對應的圖片就行。
以高德地圖為例,看看如何設定:
需要重寫GMapProvider這個類,程式碼如下:
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; } } private AMapProvider() { } static AMapProvider() { Instance = new AMapProvider(); } //根據座標和縮放,獲取對應的圖片。 public override PureImage GetTileImage(GPoint pos, int zoom) { string url = MakeTileImageUrl(pos, zoom, LanguageStr); return GetTileImageUsingHttp(url); } string MakeTileImageUrl(GPoint pos, int zoom, string language) { //http://webrd04.is.autonavi.com/appmaptile?x=5&y=2&z=3⟨=zh_cn&size=1&scale=1&style=7 string url = string.Format(UrlFormat, pos.X, pos.Y, zoom); Console.WriteLine("url:" + url); return url; } static readonly string UrlFormat = "http://webrd04.is.autonavi.com/appmaptile?x={0}&y={1}&z={2}⟨=zh_cn&size=1&scale=1&style=7"; }
最重要的函式就是 public override PureImage GetTileImage(GPoint pos, int zoom),地圖就是同一縮放比例的圖片堆砌而來。
使用控制元件
在視窗中新增控制元件:主視窗程式碼如下
<Window x:Class="GMapTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:gmap="clr-namespace:GMap.NET.WindowsPresentation;assembly=GMap.NET.WindowsPresentation" xmlns:local="clr-namespace:GMapTest" Loaded="Window_Loaded" mc:Ignorable="d"Background="#5A9EA5" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="31*"/> <ColumnDefinition Width="167*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <StackPanel Margin="5" Orientation="Horizontal" Grid.ColumnSpan="2"> <CheckBox x:Name="checkMoveFlag" Margin="5,2,2,2" Click="CheckMoveFlag_Click">標註可移動</CheckBox> <CheckBox x:Name="checkAddFlag" Margin="10,2,2,2">新增標註</CheckBox> </StackPanel> <GroupBox Grid.Row="1" Margin="0" Grid.ColumnSpan="2"> <gmap:GMapControl x:Name="MainMap" MaxZoom="24" MinZoom="1" RenderOptions.BitmapScalingMode="NearestNeighbor" UseLayoutRounding="True" SnapsToDevicePixels="True"> </gmap:GMapControl> </GroupBox> </Grid> </Window>
使用設定RenderOptions.BitmapScalingMode="NearestNeighbor",可使圖片顯示較為清晰。
新增標註
標註稱之為Marker。控制元件有一個屬性 public ObservableCollection<GMapMarker> Markers { get; }用於存放標註。新增標註就是設定好GMapMarker相關屬性就行。程式碼如下:
BitmapImage _pinSrcImage; Image CreatePinImage(GMapMarker marker) { Image img = new Image(); img.Tag = marker; img.Width = 32; img.Height = 32; if (_pinSrcImage == null) { //多個標註共用一個影象源,節省記憶體。 _pinSrcImage = new BitmapImage(new Uri("pack://application:,,,/AMap/red-dot.png", UriKind.Absolute)); _pinSrcImage.Freeze(); } img.Source = _pinSrcImage; //滑鼠熱點位置 marker.Offset = new Point(-img.Width / 2, -img.Height / 2); return img; } private void AddMaker(PointLatLng pt) { GMapMarker marker = new GMapMarker(pt); marker.Shape = CreatePinImage(marker); //將圖層新增到地圖 this.MainMap.Markers.Add(marker); }
移動標註
首先需要檢測滑鼠是否點選了標註部分。需要在MouseDown事件中,通過WPF視覺樹輔助函式來判斷(VisualTreeHelper.HitTest)。其次在MouseMove函式中,將標註移動到新的座標點。這裡是通過滑鼠左鍵移動;要實現此操作,設定控制元件拖動方式為 MainMap.DragButton = MouseButton.Right; 暨設定地圖拖動方式為滑鼠右鍵,防止與標註移動相沖突。
關聯控制元件事件:
MainMap.MouseMove += MainMap_MouseMove; MainMap.MouseDown += MainMap_MouseDown; MainMap.MouseLeftButtonUp += MainMap_MouseLeftButtonUp;
判斷滑鼠是否點選了標註部分
GMapMarker _currentElement; private void MainMap_MouseDown(object sender, MouseButtonEventArgs e) { if (checkMoveFlag.IsChecked == false) { return; } //判斷是否點選了標註 if (_currentElement == null) { Point pt = e.GetPosition(MainMap); PointLatLng point = MainMap.FromLocalToLatLng((int)pt.X, (int)pt.Y); PointHitTestParameters parameters = new PointHitTestParameters(pt); VisualTreeHelper.HitTest(MainMap, null, HitTestCallback, parameters); } } //右鍵彈起,設定標註變數為空 private void MainMap_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { _currentElement = null; } private HitTestResultBehavior HitTestCallback(HitTestResult result) { Image image = result.VisualHit as Image; if (image != null) { _currentElement = image.Tag as GMapMarker; return HitTestResultBehavior.Stop; } return HitTestResultBehavior.Continue; }
MouseMove事件中,移動標註
private void MainMap_MouseMove(object sender, MouseEventArgs e) { if (checkMoveFlag.IsChecked == true && e.LeftButton == MouseButtonState.Pressed && _currentElement != null) { //獲取座標 Point pt = e.GetPosition(MainMap); //轉換成地理座標 PointLatLng point = MainMap.FromLocalToLatLng((int)pt.X, (int)pt.Y); _currentElement.Position = point; } }
後記:
winform和WPF是開發桌面程式的兩大框架。其中WPF是最新框架,具有很多顛覆性的概念。好多人感覺WPF概念難以理解,同感覺到GMap.net對WPF的封裝也不夠好,使用起來不如winform版好用。WPF版的GMap.net相比與winform版,確實省略了一些功能。這是因為WPF本身就很強大靈活,GMap.net再加上這些功能好像多此一舉。“”標註檢測”就是一例,winform版有直接檢測標註的回撥函式,WPF版就省略了。WPF是可以通過視覺樹HitTest函式來檢查,這種檢測方法更靈活。
原始碼下載地址 ofollow,noindex"> https://download.csdn.net/download/qq_29939347/10797027 ;