没有为儿童调用ArrangeOverride?

时间:2016-06-30 14:27:19

标签: wpf canvas mvvm itemscontrol gmap.net

我正在使用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();

摘要:

  • 我有一个GMapControl ItemsControl,使用MapCanvas来地理空间定位元素。 DataTypes用于选择每个元素使用哪个DataTemplate。这适用于基于点的元素,例如标记。
  • 其中一个DataTemplates是一个ItemsControl,它使用另一个MapCanvas变体(MapOverlay)作为其ItemsPanel来在子元素之间绘制线条。当它的ArrangeOverride执行时,它在启动时起作用。
  • 平移地图有效,但是在MapOverlay中没有调用ArrangeOverride。

问题:当我的元素最初正确定位时,缩放地图(通过地图控件触发InvalidateVisual和UpdateLayout)不会导致在嵌套的MapOverlay上调用ArrangeOverride。这导致路线不再正确定位 - 它不会缩放。

关于为什么安排失效不会渗透到嵌套的MapOverlay和/或如何解决它的提示的任何建议?

附录:当地图最初位于第一个元素时,路线才正确放置 - 整个路线的纬度/经度是一个单独的问题我欢迎提出意见

1 个答案:

答案 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