Added MapPanel.AutoCollapse property

This commit is contained in:
ClemensF 2021-01-13 00:08:55 +01:00
parent ec1a018b50
commit fead75ffb9
11 changed files with 138 additions and 83 deletions

View file

@ -33,12 +33,27 @@ namespace MapControl
MapPanel.InitMapElement(this); MapPanel.InitMapElement(this);
} }
/// <summary>
/// Wrapper for the MapPanel.AutoCollapse attached property.
/// </summary>
public bool AutoCollapse
{
get { return (bool)GetValue(AutoCollapseProperty); }
set { SetValue(AutoCollapseProperty, value); }
}
/// <summary>
/// Wrapper for the MapPanel.Location attached property.
/// </summary>
public Location Location public Location Location
{ {
get { return (Location)GetValue(LocationProperty); } get { return (Location)GetValue(LocationProperty); }
set { SetValue(LocationProperty, value); } set { SetValue(LocationProperty, value); }
} }
/// <summary>
/// Path to a source property for binding the Location property.
/// </summary>
public string LocationMemberPath public string LocationMemberPath
{ {
get { return (string)GetValue(LocationMemberPathProperty); } get { return (string)GetValue(LocationMemberPathProperty); }

View file

@ -31,13 +31,8 @@ namespace MapControl
/// </summary> /// </summary>
public partial class MapPanel : Panel, IMapElement public partial class MapPanel : Panel, IMapElement
{ {
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) public static readonly DependencyProperty AutoCollapseProperty = DependencyProperty.RegisterAttached(
{ "AutoCollapse", typeof(bool), typeof(MapPanel), new PropertyMetadata(false));
if (obj is IMapElement mapElement)
{
mapElement.ParentMap = e.NewValue as MapBase;
}
}
private MapBase parentMap; private MapBase parentMap;
@ -52,26 +47,58 @@ namespace MapControl
InitMapElement(this); InitMapElement(this);
} }
/// <summary>
/// Gets a value that controls whether an element's Visibility is automatically
/// set to Collapsed when it is located outside the visible viewport area.
/// </summary>
public static bool GetAutoCollapse(FrameworkElement element)
{
return (bool)element.GetValue(AutoCollapseProperty);
}
/// <summary>
/// Sets the AutoCollapse property.
/// </summary>
public static void SetAutoCollapse(FrameworkElement element, bool value)
{
element.SetValue(AutoCollapseProperty, value);
}
/// <summary>
/// Gets the geodetic Location of an element.
/// </summary>
public static Location GetLocation(FrameworkElement element) public static Location GetLocation(FrameworkElement element)
{ {
return (Location)element.GetValue(LocationProperty); return (Location)element.GetValue(LocationProperty);
} }
/// <summary>
/// Sets the geodetic Location of an element.
/// </summary>
public static void SetLocation(FrameworkElement element, Location value) public static void SetLocation(FrameworkElement element, Location value)
{ {
element.SetValue(LocationProperty, value); element.SetValue(LocationProperty, value);
} }
/// <summary>
/// Gets the BoundingBox of an element.
/// </summary>
public static BoundingBox GetBoundingBox(FrameworkElement element) public static BoundingBox GetBoundingBox(FrameworkElement element)
{ {
return (BoundingBox)element.GetValue(BoundingBoxProperty); return (BoundingBox)element.GetValue(BoundingBoxProperty);
} }
/// <summary>
/// Sets the BoundingBox of an element.
/// </summary>
public static void SetBoundingBox(FrameworkElement element, BoundingBox value) public static void SetBoundingBox(FrameworkElement element, BoundingBox value)
{ {
element.SetValue(BoundingBoxProperty, value); element.SetValue(BoundingBoxProperty, value);
} }
/// <summary>
/// Gets the position of an element in view coordinates.
/// </summary>
public static Point? GetViewPosition(FrameworkElement element) public static Point? GetViewPosition(FrameworkElement element)
{ {
return (Point?)element.GetValue(ViewPositionProperty); return (Point?)element.GetValue(ViewPositionProperty);
@ -80,8 +107,13 @@ namespace MapControl
/// <summary> /// <summary>
/// Returns the view position of a Location. /// Returns the view position of a Location.
/// </summary> /// </summary>
public Point GetViewPosition(Location location) public Point? GetViewPosition(Location location)
{ {
if (location == null)
{
return null;
}
var pos = parentMap.LocationToView(location); var pos = parentMap.LocationToView(location);
if (parentMap.MapProjection.IsNormalCylindrical && if (parentMap.MapProjection.IsNormalCylindrical &&
@ -175,19 +207,32 @@ namespace MapControl
{ {
foreach (var element in Children.OfType<FrameworkElement>()) foreach (var element in Children.OfType<FrameworkElement>())
{ {
var location = GetLocation(element); var position = GetViewPosition(GetLocation(element));
if (location != null) SetViewPosition(element, position);
if (GetAutoCollapse(element))
{ {
var position = GetViewPosition(location); if (position.HasValue &&
(position.Value.X < 0d ||
position.Value.Y < 0d ||
position.Value.X > parentMap.RenderSize.Width ||
position.Value.Y > parentMap.RenderSize.Height))
{
element.SetValue(VisibilityProperty, Visibility.Collapsed);
}
else
{
element.ClearValue(VisibilityProperty);
}
}
SetViewPosition(element, position); if (position.HasValue)
ArrangeElement(element, position); {
ArrangeElement(element, position.Value);
} }
else else
{ {
SetViewPosition(element, null);
var boundingBox = GetBoundingBox(element); var boundingBox = GetBoundingBox(element);
if (boundingBox != null) if (boundingBox != null)
@ -314,5 +359,13 @@ namespace MapControl
element.Arrange(rect); element.Arrange(rect);
} }
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is IMapElement mapElement)
{
mapElement.ParentMap = e.NewValue as MapBase;
}
}
} }
} }

View file

@ -29,6 +29,15 @@ namespace MapControl
MapPanel.InitMapElement(this); MapPanel.InitMapElement(this);
} }
/// <summary>
/// Wrapper for the MapPanel.AutoCollapse attached property.
/// </summary>
public bool AutoCollapse
{
get { return (bool)GetValue(AutoCollapseProperty); }
set { SetValue(AutoCollapseProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets a Location that is used as /// Gets or sets a Location that is used as
/// - either the origin point of a geometry specified in cartesian map units (meters) /// - either the origin point of a geometry specified in cartesian map units (meters)

View file

@ -17,13 +17,18 @@ namespace MapControl
/// </summary> /// </summary>
public class Pushpin : ContentControl public class Pushpin : ContentControl
{ {
public static readonly DependencyProperty LocationProperty =
#if WINDOWS_UWP #if WINDOWS_UWP
DependencyProperty.Register( public static readonly DependencyProperty AutoCollapseProperty = DependencyProperty.Register(
nameof(Location), typeof(Location), typeof(Pushpin), nameof(AutoCollapse), typeof(bool), typeof(Pushpin),
new PropertyMetadata(null, (o, e) => MapPanel.SetLocation((FrameworkElement)o, (Location)e.NewValue))); new PropertyMetadata(false, (o, e) => MapPanel.SetAutoCollapse((FrameworkElement)o, (bool)e.NewValue)));
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
nameof(Location), typeof(Location), typeof(Pushpin),
new PropertyMetadata(null, (o, e) => MapPanel.SetLocation((FrameworkElement)o, (Location)e.NewValue)));
#else #else
MapPanel.LocationProperty.AddOwner(typeof(Pushpin)); public static readonly DependencyProperty AutoCollapseProperty = MapPanel.AutoCollapseProperty.AddOwner(typeof(Pushpin));
public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(Pushpin));
#endif #endif
public Pushpin() public Pushpin()
{ {
@ -32,6 +37,18 @@ namespace MapControl
MapPanel.InitMapElement(this); MapPanel.InitMapElement(this);
} }
/// <summary>
/// Wrapper for the MapPanel.AutoCollapse attached property.
/// </summary>
public bool AutoCollapse
{
get { return (bool)GetValue(AutoCollapseProperty); }
set { SetValue(AutoCollapseProperty, value); }
}
/// <summary>
/// Wrapper for the MapPanel.Location attached property.
/// </summary>
public Location Location public Location Location
{ {
get { return (Location)GetValue(LocationProperty); } get { return (Location)GetValue(LocationProperty); }

View file

@ -11,6 +11,10 @@ namespace MapControl
{ {
public partial class MapItem public partial class MapItem
{ {
public static readonly DependencyProperty AutoCollapseProperty = DependencyProperty.Register(
nameof(AutoCollapse), typeof(bool), typeof(MapItem),
new PropertyMetadata(false, (o, e) => MapPanel.SetAutoCollapse((FrameworkElement)o, (bool)e.NewValue)));
public static readonly DependencyProperty LocationProperty = DependencyProperty.Register( public static readonly DependencyProperty LocationProperty = DependencyProperty.Register(
nameof(Location), typeof(Location), typeof(MapItem), nameof(Location), typeof(Location), typeof(MapItem),
new PropertyMetadata(null, (o, e) => MapPanel.SetLocation((FrameworkElement)o, (Location)e.NewValue))); new PropertyMetadata(null, (o, e) => MapPanel.SetLocation((FrameworkElement)o, (Location)e.NewValue)));

View file

@ -14,6 +14,10 @@ namespace MapControl
{ {
public partial class MapPath : Path public partial class MapPath : Path
{ {
public static readonly DependencyProperty AutoCollapseProperty = DependencyProperty.Register(
nameof(AutoCollapse), typeof(bool), typeof(MapPath),
new PropertyMetadata(false, (o, e) => MapPanel.SetAutoCollapse((FrameworkElement)o, (bool)e.NewValue)));
#region Methods used only by derived classes MapPolyline and MapPolygon #region Methods used only by derived classes MapPolyline and MapPolygon
protected void DataCollectionPropertyChanged(DependencyPropertyChangedEventArgs e) protected void DataCollectionPropertyChanged(DependencyPropertyChangedEventArgs e)

View file

@ -11,6 +11,8 @@ namespace MapControl
{ {
public partial class MapItem public partial class MapItem
{ {
public static readonly DependencyProperty AutoCollapseProperty = MapPanel.AutoCollapseProperty.AddOwner(typeof(MapItem));
public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(MapItem)); public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(MapItem));
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)

View file

@ -14,6 +14,8 @@ namespace MapControl
{ {
public partial class MapPath : Shape, IWeakEventListener public partial class MapPath : Shape, IWeakEventListener
{ {
public static readonly DependencyProperty AutoCollapseProperty = MapPanel.AutoCollapseProperty.AddOwner(typeof(MapPath));
public static readonly DependencyProperty DataProperty = Path.DataProperty.AddOwner(typeof(MapPath)); public static readonly DependencyProperty DataProperty = Path.DataProperty.AddOwner(typeof(MapPath));
public Geometry Data public Geometry Data

View file

@ -21,6 +21,7 @@
</Style> </Style>
<Style x:Key="PointItemStyle" TargetType="map:MapItem"> <Style x:Key="PointItemStyle" TargetType="map:MapItem">
<Setter Property="AutoCollapse" Value="True"/>
<Setter Property="LocationMemberPath" Value="Location"/> <Setter Property="LocationMemberPath" Value="Location"/>
<Setter Property="Foreground" Value="Black"/> <Setter Property="Foreground" Value="Black"/>
<Setter Property="Template"> <Setter Property="Template">
@ -76,6 +77,7 @@
</Style> </Style>
<Style x:Key="PushpinItemStyle" TargetType="map:MapItem"> <Style x:Key="PushpinItemStyle" TargetType="map:MapItem">
<Setter Property="AutoCollapse" Value="True"/>
<Setter Property="LocationMemberPath" Value="Location"/> <Setter Property="LocationMemberPath" Value="Location"/>
<Setter Property="VerticalAlignment" Value="Bottom"/> <Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Foreground" Value="Black"/> <Setter Property="Foreground" Value="Black"/>
@ -130,7 +132,7 @@
<map:MapItemsControl ItemsSource="{Binding Pushpins}" <map:MapItemsControl ItemsSource="{Binding Pushpins}"
ItemContainerStyle="{StaticResource PushpinItemStyle}"/> ItemContainerStyle="{StaticResource PushpinItemStyle}"/>
<map:Pushpin Background="Yellow" Foreground="Blue" Content="N 53° 30' E 8° 12'"> <map:Pushpin AutoCollapse="True" Background="Yellow" Foreground="Blue" Content="N 53° 30' E 8° 12'">
<map:Pushpin.Location> <map:Pushpin.Location>
<map:Location Latitude="53.5" Longitude="8.2"/> <map:Location Latitude="53.5" Longitude="8.2"/>
</map:Pushpin.Location> </map:Pushpin.Location>

View file

@ -1,38 +0,0 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using MapControl;
namespace WpfApplication
{
public class LocationToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var visibility = Visibility.Collapsed;
if (values.Length == 2 && values[0] is MapBase && values[1] is Point?)
{
var parentMap = (MapBase)values[0];
var position = (Point?)values[1];
if (position.HasValue &&
position.Value.X >= 0d &&
position.Value.Y >= 0d &&
position.Value.X <= parentMap.ActualWidth &&
position.Value.Y <= parentMap.ActualHeight)
{
visibility = Visibility.Visible;
}
}
return visibility;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View file

@ -7,8 +7,6 @@
Title="XAML MapControl - WPF Test Application" Height="600" Width="900" Title="XAML MapControl - WPF Test Application" Height="600" Width="900"
Stylus.IsPressAndHoldEnabled="False"> Stylus.IsPressAndHoldEnabled="False">
<Window.Resources> <Window.Resources>
<local:LocationToVisibilityConverter x:Key="LocationToVisibilityConverter"/>
<DataTemplate x:Key="PolylineItemTemplate"> <DataTemplate x:Key="PolylineItemTemplate">
<map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/> <map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/>
</DataTemplate> </DataTemplate>
@ -25,6 +23,7 @@
<Style x:Key="PointItemStyle" TargetType="map:MapItem"> <Style x:Key="PointItemStyle" TargetType="map:MapItem">
<EventSetter Event="TouchDown" Handler="MapItemTouchDown"/> <EventSetter Event="TouchDown" Handler="MapItemTouchDown"/>
<Setter Property="AutoCollapse" Value="True"/>
<Setter Property="Location" Value="{Binding Location}"/> <Setter Property="Location" Value="{Binding Location}"/>
<Setter Property="Foreground" Value="Black"/> <Setter Property="Foreground" Value="Black"/>
<Setter Property="Template"> <Setter Property="Template">
@ -80,17 +79,10 @@
<Style x:Key="PushpinItemStyle" TargetType="map:MapItem"> <Style x:Key="PushpinItemStyle" TargetType="map:MapItem">
<EventSetter Event="TouchDown" Handler="MapItemTouchDown"/> <EventSetter Event="TouchDown" Handler="MapItemTouchDown"/>
<Setter Property="AutoCollapse" Value="True"/>
<Setter Property="Location" Value="{Binding Location}"/> <Setter Property="Location" Value="{Binding Location}"/>
<Setter Property="VerticalAlignment" Value="Bottom"/> <Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Foreground" Value="Black"/> <Setter Property="Foreground" Value="Black"/>
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
<Binding Path="(map:MapPanel.ViewPosition)" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="map:MapItem"> <ControlTemplate TargetType="map:MapItem">
@ -123,7 +115,7 @@
<RowDefinition/> <RowDefinition/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<map:Map x:Name="map" ZoomLevel="11" MaxZoomLevel="21" MouseWheelZoomDelta="0.5" <map:Map x:Name="map" ZoomLevel="11" MaxZoomLevel="21" MouseWheelZoomDelta="1"
Center="{Binding MapCenter}" Center="{Binding MapCenter}"
MapLayer="{Binding MapLayers.CurrentMapLayer}" MapLayer="{Binding MapLayers.CurrentMapLayer}"
MapProjection="{Binding SelectedValue, ElementName=projectionComboBox, MapProjection="{Binding SelectedValue, ElementName=projectionComboBox,
@ -153,25 +145,18 @@
<map:MapItemsControl ItemsSource="{Binding Pushpins}" <map:MapItemsControl ItemsSource="{Binding Pushpins}"
ItemContainerStyle="{StaticResource PushpinItemStyle}"/> ItemContainerStyle="{StaticResource PushpinItemStyle}"/>
<map:Pushpin Location="65,-18" Content="Iceland"/> <map:Pushpin AutoCollapse="True" Location="65,-18" Content="Iceland"/>
<map:Pushpin Location="71,25" Content="Norway"/> <map:Pushpin AutoCollapse="True" Location="71,25" Content="Norway"/>
<map:Pushpin Location="35,33" Content="Cyprus"/> <map:Pushpin AutoCollapse="True" Location="35,33" Content="Cyprus"/>
<map:Pushpin Location="28.25,-16.5" Content="Tenerife"/> <map:Pushpin AutoCollapse="True" Location="28.25,-16.5" Content="Tenerife"/>
<map:MapPath Location="53.5,8.2" Stroke="Blue" StrokeThickness="3" Fill="#1F007F00"> <map:MapPath AutoCollapse="True" Location="53.5,8.2" Stroke="Blue" StrokeThickness="3" Fill="#1F007F00">
<map:MapPath.Data> <map:MapPath.Data>
<EllipseGeometry RadiusX="1852" RadiusY="1852"/> <EllipseGeometry RadiusX="1852" RadiusY="1852"/>
</map:MapPath.Data> </map:MapPath.Data>
</map:MapPath> </map:MapPath>
<map:Pushpin Location="53.5,8.2" Background="Yellow" Foreground="Blue" Content="N 53°30' E 8°12'"> <map:Pushpin AutoCollapse="True" Location="53.5,8.2" Background="Yellow" Foreground="Blue" Content="N 53°30' E 8°12'"/>
<map:Pushpin.Visibility>
<MultiBinding Converter="{StaticResource LocationToVisibilityConverter}">
<Binding Path="(map:MapPanel.ParentMap)" RelativeSource="{RelativeSource Self}"/>
<Binding Path="(map:MapPanel.ViewPosition)" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</map:Pushpin.Visibility>
</map:Pushpin>
</map:Map> </map:Map>
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#AFFFFFFF"> <Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#AFFFFFFF">