我正在使用GreatMaps.NET库(https://greatmaps.codeplex.com/)的面向MVVM的分支,但我的问题归结为使用自定义Canvas作为ItemsControl的ItemsPanel的基本问题。基本上,地图是ItemsControl,MapCanvas将其子项放置如下:
protected override Size ArrangeOverride(Size arrangeSize)
{
foreach (UIElement child in Children)
{
PointLatLng position = new PointLatLng(GetTop(child), GetLeft(child));
GMapControl map = Owner as GMapControl;
if (map != null)
{
GPoint p = map.FromLatLngToLocal(position);
p.Offset(-(long)(map.MapTranslateTransform.X + child.DesiredSize.Width * 0.5), -(long)(map.MapTranslateTransform.Y + child.DesiredSize.Height * 0.5));
Rect rect = new Rect(p.X, p.Y, child.DesiredSize.Width, child.DesiredSize.Height);
child.Arrange(rect);
}
}
return arrangeSize;
}
这是有效的,因为我的ItemContainerStyle在ViewModel中为每个地图项绑定纬度和经度,如下所示(与ZIndex一起,我将其设置为99作为占位符):
<Setter Property="Canvas.Left" Value="{Binding Longitude}" />
<Setter Property="Canvas.Top" Value="{Binding Latitude}" />
<Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}" />
我正在使用DataTemplates和DataType字段来调整每个元素的显示方式,并且该部分正常工作。
我需要将元素(例如地图上的路线行)作为点元素而不是子元素序列。为此,我只是按照模式,制作了一个DataTemplate,我使用另一个MapCanvas绑定到与其所有者相同的MapControl(这里,MapOverlay只是MapCanvas的一个副本,它覆盖OnRender以在其子节点之间绘制线条):
<DataTemplate DataType="{x:Type viewModels:RouteViewModel}">
<ItemsControl ItemsSource="{Binding Locations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<wpf:MapOverlay Name="MapOverlay" Owner="{Binding Path=., RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type wpf:GMapControl}}}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Longitude}" />
<Setter Property="Canvas.Top" Value="{Binding Latitude}" />
<Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Fill="Blue" Stroke="Black" Width="10" Height="10"></Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
为了保持绑定工作,RouteViewModel仍然有自己的Lat / Lng,它似乎只有在我将它们放置在路径上的点列表的起始点时才起作用:
public double Latitude => Locations.Select(loc => loc.Latitude).FirstOrDefault();
public double Longitude => Locations.Select(loc => loc.Longitude).FirstOrDefault();
摘要:
问题:当我的元素最初正确定位时,缩放地图(通过地图控件触发InvalidateVisual和UpdateLayout)不会导致在嵌套的MapOverlay上调用ArrangeOverride。这导致路线不再正确定位 - 它不会缩放。
关于为什么安排失效不会渗透到嵌套的MapOverlay和/或如何解决它的提示的任何建议?
附录:当地图最初位于第一个元素时,路线才正确放置 - 整个路线的纬度/经度是一个单独的问题我欢迎提出意见
答案 0 :(得分:0)
实际上并不是您问题的答案,但它可能会让您大致了解如何显示路线,即按行连接的圆圈集合。
以下示例使用XAML MapControl库,但可能会基于具有某种MapItemsControl
的任何其他地图库(例如MS Bing地图)来实施。
我们的想法是拥有构成路线的Location
个实例集合。您将拥有MapPolyline
并将其Locations
属性绑定到路由点集合。然后在其上放置MapItemsControl
并将其ItemsSource
绑定到同一个集合。请注意,ItemTemplate
使用带有EllipseGeometries而不是Ellipses的Path控件,因为它们位于点位置的中心,而省略号是顶部/左对齐。
<map:MapPanel>
<map:MapPolyline Locations="{Binding RouteLocations}"
Stroke="DarkBlue" StrokeThickness="3"/>
<map:MapItemsControl ItemsSource="{Binding RouteLocations}">
<map:MapItemsControl.ItemContainerStyle>
<Style TargetType="map:MapItem">
<Setter Property="map:MapPanel.Location" Value="{Binding}"/>
</Style>
</map:MapItemsControl.ItemContainerStyle>
<map:MapItemsControl.ItemTemplate>
<DataTemplate>
<Path Fill="Red">
<Path.Data>
<EllipseGeometry RadiusX="5" RadiusY="5"/>
</Path.Data>
</Path>
</DataTemplate>
</map:MapItemsControl.ItemTemplate>
</map:MapItemsControl>
</map:MapPanel>
如果路线点不是Location
s,您可以在两个绑定中使用绑定转换器将路线点类型转换为Location
。