WPF在Gmap.net中將Marker動起來
前一段時間說過一篇繪製極坐標的,這段時間對它進行了改造已經今非昔比了,功能實現了很多,我目的是讓Marker動起來,然後還會繪製Route,上篇也就是簡單的繪製了Route,沒有關於Marker的相關知識。
那個Circle有一定的改造,原來的純色改成了漸變,這個你可以提前想好,不過在程式碼中你要做好適配,將 System.draw.color 轉換成了 Media.Color ,取其中的ARGB值。
public Circle(string name, int radius,string[] vs) { Radius = radius; m_viewModelCircle = new ViewModelCircle(); m_viewModelCircle.CircleDis = name; this.DataContext = m_viewModelCircle; InitializeComponent(); //控制circle RadialGradientBrush radialGradient = new RadialGradientBrush(); var obj = ColorTranslator.FromHtml(vs[0]); var ob2 = ColorTranslator.FromHtml(vs[1]); var ob3 = ColorTranslator.FromHtml(vs[2]); this.circle.Stroke= new SolidColorBrush(System.Windows.Media.Color.FromArgb(ob3.A, ob3.R, ob3.G, ob3.B)); radialGradient.GradientStops.Add(new GradientStop(System.Windows.Media.Color.FromArgb(obj.A, obj.R, obj.G, obj.B), 0.75)); radialGradient.GradientStops.Add(new GradientStop(System.Windows.Media.Color.FromArgb(ob2.A, ob2.R, ob2.G, ob2.B), 1)); this.circle.Fill = radialGradient; }
我們都知道在Wpf的Gmap.net中沒有了GMapOverlay 概念,所有的東西都在Marker中操作,這樣其實有一個優點,就是把Overlay和Marker混合在一起更好管理,你可以通過Tag來尋找你對象,非常輕便,但設計者不是這麼認為的,可能是某些原理沒法走通。
最基本的右擊在map中添加標點可以這麼操作。
private void RadarMap_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { Point clickPoint = e.GetPosition(radarMap); PointLatLng point = radarMap.FromLocalToLatLng((int)clickPoint.X, (int)clickPoint.Y); id += 1; GMapMarker currentMarker = new GMapMarker(point); { currentMarker.Shape = new CustomMarker(id, currentMarker); //(currentMarker.Shape as CustomMarker).SetContent(point, "1"); 這種方法可以觸發SetContent currentMarker.ZIndex = -1; currentMarker.Position = point; radarMap.Markers.Add(currentMarker); this.Focus(); } }
程式碼中可以發現我們可以輕鬆將gmap的marker shape屬性 ,隨後轉換成原來的marker類型,輕鬆調用屬於它的方法,所以它的生命周期是等待它所在gmap中的marker被銷毀才會被dispose,至於我的標點數據是從那裡接受的,我只是啟用兩個Demo而已,發了個udp通訊,一般來說都是使用結構體來接受,傳入的Byte值,我們進行逆轉。
public static object BytesToStruct(byte[] buf, int len, Type type) { // int len = Marshal.SizeOf(buf); object rtn; IntPtr buffer = Marshal.AllocHGlobal(len); Marshal.Copy(buf, 0, buffer, len); rtn = Marshal.PtrToStructure(buffer, type); Marshal.FreeHGlobal(buffer); return rtn; }
下面的程式碼是關於繪製,以及判斷marker是否存在,如果存在則修改Postion,而且還要重新繪製Route,每個Route是對應著它的Marker,所以需要一個字典,每次重新繪製的時候,先將Route全部刪除,隨後重新所有的點,然後進行繪製Route,這個程式碼可能性能上有缺陷,但也是沒有辦法。
List<RadarTargetInfo> dislist = new List<RadarTargetInfo>(); //已經添加的集合 public List<RadarTargetInfo> addlist = new List<RadarTargetInfo>(); //用於畫線 Dictionary<string,List<PointLatLng>> pointLatLngsDic = new Dictionary<string,List<PointLatLng>>(); //標點和數據id的關係 List<MarkerDataRole> roleList = new List<MarkerDataRole>(); /// <summary> /// 檢查數據 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void CheckData(object sender, EventArgs e) { if (CurrentMarkerContext.list.Count == 0) { return; } //應該添加的數據 var list = CurrentMarkerContext.list.Except(addlist).ToList(); addlist.AddRange(list); dislist.Clear(); foreach (var group in list.GroupBy(u => u.Id)) { int flyId = group.Key; RadarTargetInfo radarTarget = new RadarTargetInfo(); PointLatLng currentPoint = new PointLatLng(); foreach (var item in group) { PointLatLng point = new PointLatLng(item.Latitude, item.Longitude); currentPoint = point; //代表沒有 if (roleList.FirstOrDefault(u => u.dataId == flyId) == null) { GMapMarker currentMarker = new GMapMarker(point); { currentMarker.Shape = new CustomMarker(flyId, currentMarker); currentMarker.ZIndex = -1; currentMarker.Tag = flyId; currentMarker.Position = point; radarMap.Markers.Add(currentMarker); } roleList.Add(new MarkerDataRole(){dataId = flyId,markerId = flyId}); } else { radarMap.Markers.Where(u => u.Tag != null).Where(u => Convert.ToInt32(u.Tag) == flyId).FirstOrDefault().Position = point; } var str = flyId.ToString(); if (pointLatLngsDic.ContainsKey(str)) { pointLatLngsDic[str].Add(point); } else { var value = new List<PointLatLng>(); value.Add(point); pointLatLngsDic.Add(str, value); } radarTarget = item; } dislist.Add(radarTarget); //這裡找到flyId (radarMap.Markers.Where(u => Convert.ToInt32(u.Tag) == flyId).FirstOrDefault().Shape as CustomMarker).SetContent(currentPoint, flyId); } this.雷達目標數據.ItemsSource = dislist; foreach (var item in radarMap.Markers.Where(u => u.Tag != null).Where(u => u.Tag.ToString() == "line").ToList()) { radarMap.Markers.Remove(item); } foreach (var item in pointLatLngsDic) { GMapRoute gmRoute = new GMapRoute(pointLatLngsDic[item.Key]) { Shape = new Line() { StrokeThickness = 4 },Tag = "line" }; radarMap.Markers.Add(gmRoute); } }
還有一個需要強調的是,上面說過可以通過Shape找到本身調用其方法,那個Marker上面的文本就是這麼改的。
public void SetContent(PointLatLng point, int pihao) { this.批號.Content = pihao.ToString(); this.緯度.Content = "緯度:" + ((int)(point.Lat * 1000) / 1000.0).ToString(); this.經度.Content = "緯度:" + ((int)(point.Lng * 1000) / 1000.0).ToString(); }
(radarMap.Markers.Where(u => Convert.ToInt32(u.Tag) == flyId).FirstOrDefault().Shape as CustomMarker).SetContent(currentPoint, flyId);
還有就是至於我的Wpf程式自適應問題,我都是用Viewbox做的,因為前端UI他老是玩Margin,so…你懂的!人家都是Blend for visual Studio 給搞的。也只能見諒了.