WPF地图无图层ZIndex:如何在不降低透明度的多边形下显示地名?
我完全理解你的痛点——WPF的Map控件不像UWP那样有ZIndex属性直接调整层级,想要完全不透明的多边形又不挡住地名确实有点棘手。不过这里有两个可靠的方案,先给你最直接的那个:
方案一:利用Map.Layers集合(推荐)
微软的WPF Map控件(Microsoft.Maps.MapControl.WPF)其实有一个专门的Layers集合,这个集合里的图层默认绘制在地图瓦片层(TileLayer)之上,地名标签层(LabelsLayer)之下。而你之前用myMap.Children.Add()添加的元素,是在LabelsLayer的上方,所以才会遮挡地名。
只需要把你的多边形放到自定义的MapLayer里,再添加到Map.Layers中即可:
// 创建你的多边形,保持Opacity=1完全不透明 MapPolygon lcMapPolygon = new MapPolygon { StrokeThickness = 1, Stroke = new SolidColorBrush(Colors.White), Locations = lcBasicGeopositions, Fill = new SolidColorBrush(GetFillColor(lcDataValue)), Opacity = 1, // 这里保持1即可,不用降低 Tag = new MapPolygonTag(pmLayerName, lcPlacemark.Name, lcDataValueString) }; // 创建一个MapLayer来容纳多边形 var polygonLayer = new MapLayer(); polygonLayer.Children.Add(lcMapPolygon); // 关键:添加到Map.Layers而不是Map.Children! myMap.Layers.Add(polygonLayer);
这样操作后,多边形会显示在地图瓦片上面,而地名标签会叠加在多边形之上,完美满足你的需求——既保持多边形完全不透明,又能看到地名。
方案二:手动调整可视化树层级(备选)
如果因为控件版本或自定义模板的原因,Layers集合的层级不符合预期,你可以手动找到LabelsLayer,把多边形图层插入到它前面:
首先,写一个辅助方法遍历可视化树查找元素:
private T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is T typedChild) return typedChild; var result = FindVisualChild<T>(child); if (result != null) return result; } return null; }
然后在Map加载完成后(比如Loaded事件中)执行以下代码:
private void myMap_Loaded(object sender, RoutedEventArgs e) { // 创建多边形和图层(和方案一一样) MapPolygon lcMapPolygon = new MapPolygon { StrokeThickness = 1, Stroke = new SolidColorBrush(Colors.White), Locations = lcBasicGeopositions, Fill = new SolidColorBrush(GetFillColor(lcDataValue)), Opacity = 1, Tag = new MapPolygonTag(pmLayerName, lcPlacemark.Name, lcDataValueString) }; var polygonLayer = new MapLayer(); polygonLayer.Children.Add(lcMapPolygon); // 找到LabelsLayer var labelsLayer = FindVisualChild<LabelsLayer>(myMap); if (labelsLayer != null) { var parentPanel = VisualTreeHelper.GetParent(labelsLayer) as Panel; if (parentPanel != null) { // 插入到LabelsLayer的前面,确保地名在多边形上方 int index = parentPanel.Children.IndexOf(labelsLayer); parentPanel.Children.Insert(index, polygonLayer); } } }
注意一定要在Map加载完成后执行,否则控件模板还没初始化,找不到LabelsLayer。
为什么你之前尝试放底层没成功?
你之前尝试把多边形放在地图底层,应该是错误地往TileLayer下面或者Map.Children的底层添加,但TileLayer本身就是最底层,而Map.Children的元素默认都在LabelsLayer之上,所以根本无法让多边形处于瓦片和地名之间。而上面的方案正是解决了这个层级问题,把多边形精准地放在了瓦片和地名之间的层级。
内容的提问来源于stack exchange,提问作者Liviu Sosu

