XAML-Map-Control/MapControl/MapPanel.cs

255 lines
9.2 KiB
C#
Raw Normal View History

2012-05-04 12:52:20 +02:00
// WPF MapControl - http://wpfmapcontrol.codeplex.com/
// Copyright © 2012 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
2012-04-25 22:02:53 +02:00
using System.Windows;
using System.Windows.Controls;
namespace MapControl
{
2012-05-04 12:52:20 +02:00
/// <summary>
/// Positions child elements on a Map. A child element's position is specified by the
/// attached property Location, given as geographic location with latitude and longitude.
/// The attached property ViewportPosition gets a child element's position in viewport
/// coordinates. IsInsideMapBounds indicates if the viewport coordinates are located
/// inside the visible part of the map.
/// </summary>
2012-08-08 20:42:06 +02:00
public class MapPanel : Panel
2012-04-25 22:02:53 +02:00
{
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
"ParentMap", typeof(Map), typeof(MapPanel),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
public static readonly DependencyProperty LocationProperty = DependencyProperty.RegisterAttached(
2012-05-04 12:52:20 +02:00
"Location", typeof(Location), typeof(MapPanel),
2012-04-25 22:02:53 +02:00
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, LocationPropertyChanged));
2012-05-04 12:52:20 +02:00
private static readonly DependencyPropertyKey ViewportPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
"ViewportPosition", typeof(Point), typeof(MapPanel), null);
2012-04-25 22:02:53 +02:00
2012-05-04 12:52:20 +02:00
private static readonly DependencyPropertyKey IsInsideMapBoundsPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
"IsInsideMapBounds", typeof(bool), typeof(MapPanel), null);
2012-04-25 22:02:53 +02:00
2012-05-04 12:52:20 +02:00
public static readonly DependencyProperty ViewportPositionProperty = ViewportPositionPropertyKey.DependencyProperty;
public static readonly DependencyProperty IsInsideMapBoundsProperty = IsInsideMapBoundsPropertyKey.DependencyProperty;
2012-04-25 22:02:53 +02:00
public MapPanel()
{
ClipToBounds = true;
}
public Map ParentMap
{
get { return (Map)GetValue(ParentMapProperty); }
}
public static Map GetParentMap(UIElement element)
{
return (Map)element.GetValue(ParentMapProperty);
}
2012-05-04 12:52:20 +02:00
public static Location GetLocation(UIElement element)
2012-04-25 22:02:53 +02:00
{
2012-05-04 12:52:20 +02:00
return (Location)element.GetValue(LocationProperty);
2012-04-25 22:02:53 +02:00
}
2012-05-04 12:52:20 +02:00
public static void SetLocation(UIElement element, Location value)
2012-04-25 22:02:53 +02:00
{
element.SetValue(LocationProperty, value);
}
2012-05-04 12:52:20 +02:00
public static bool HasViewportPosition(UIElement element)
{
return element.ReadLocalValue(ViewportPositionProperty) != DependencyProperty.UnsetValue;
}
public static Point GetViewportPosition(UIElement element)
2012-04-25 22:02:53 +02:00
{
2012-05-04 12:52:20 +02:00
return (Point)element.GetValue(ViewportPositionProperty);
2012-04-25 22:02:53 +02:00
}
2012-05-04 12:52:20 +02:00
public static bool GetIsInsideMapBounds(UIElement element)
2012-04-25 22:02:53 +02:00
{
2012-05-04 12:52:20 +02:00
return (bool)element.GetValue(IsInsideMapBoundsProperty);
2012-04-25 22:02:53 +02:00
}
protected override Size MeasureOverride(Size availableSize)
{
Size infiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
foreach (UIElement element in InternalChildren)
{
element.Measure(infiniteSize);
}
return new Size();
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement element in InternalChildren)
{
2012-05-04 12:52:20 +02:00
object viewportPosition = element.ReadLocalValue(ViewportPositionProperty);
2012-04-25 22:02:53 +02:00
2012-05-04 12:52:20 +02:00
if (viewportPosition == DependencyProperty.UnsetValue ||
!ArrangeElement(element, (Point)viewportPosition))
2012-04-25 22:02:53 +02:00
{
ArrangeElement(element, finalSize);
}
}
return finalSize;
}
2012-08-08 20:42:06 +02:00
protected virtual void OnViewportChanged()
2012-04-25 22:02:53 +02:00
{
2012-08-08 20:42:06 +02:00
Map parentMap = ParentMap;
2012-04-25 22:02:53 +02:00
foreach (UIElement element in InternalChildren)
{
2012-05-04 12:52:20 +02:00
Location location = GetLocation(element);
2012-04-25 22:02:53 +02:00
2012-05-04 12:52:20 +02:00
if (location != null)
2012-04-25 22:02:53 +02:00
{
2012-05-04 12:52:20 +02:00
SetViewportPosition(element, parentMap, location);
2012-04-25 22:02:53 +02:00
}
}
}
2012-08-08 20:42:06 +02:00
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
2012-04-25 22:02:53 +02:00
{
2012-08-08 20:42:06 +02:00
MapPanel mapPanel = obj as MapPanel;
2012-04-25 22:02:53 +02:00
2012-08-08 20:42:06 +02:00
if (mapPanel != null)
2012-04-25 22:02:53 +02:00
{
2012-08-08 20:42:06 +02:00
Map oldParentMap = eventArgs.OldValue as Map;
Map newParentMap = eventArgs.NewValue as Map;
2012-04-25 22:02:53 +02:00
2012-08-08 20:42:06 +02:00
if (oldParentMap != null && oldParentMap != mapPanel)
{
oldParentMap.ViewportChanged -= mapPanel.OnViewportChanged;
}
2012-04-25 22:02:53 +02:00
2012-08-08 20:42:06 +02:00
if (newParentMap != null && newParentMap != mapPanel)
{
newParentMap.ViewportChanged += mapPanel.OnViewportChanged;
}
2012-04-25 22:02:53 +02:00
}
}
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
{
UIElement element = (UIElement)obj;
2012-05-04 12:52:20 +02:00
Location location = (Location)eventArgs.NewValue;
2012-04-25 22:02:53 +02:00
Map parentMap;
2012-05-04 12:52:20 +02:00
if (location != null && (parentMap = GetParentMap(element)) != null)
2012-04-25 22:02:53 +02:00
{
2012-05-04 12:52:20 +02:00
SetViewportPosition(element, parentMap, location);
2012-04-25 22:02:53 +02:00
}
else
{
2012-05-04 12:52:20 +02:00
element.ClearValue(ViewportPositionPropertyKey);
element.ClearValue(IsInsideMapBoundsPropertyKey);
2012-04-25 22:02:53 +02:00
element.Arrange(new Rect());
}
}
2012-05-04 12:52:20 +02:00
private static void SetViewportPosition(UIElement element, Map parentMap, Location location)
2012-04-25 22:02:53 +02:00
{
2012-05-04 12:52:20 +02:00
Point viewportPosition = parentMap.LocationToViewportPoint(location);
2012-04-25 22:02:53 +02:00
2012-05-04 12:52:20 +02:00
element.SetValue(ViewportPositionPropertyKey, viewportPosition);
element.SetValue(IsInsideMapBoundsPropertyKey,
viewportPosition.X >= 0d && viewportPosition.X <= parentMap.ActualWidth &&
viewportPosition.Y >= 0d && viewportPosition.Y <= parentMap.ActualHeight);
2012-04-25 22:02:53 +02:00
2012-05-04 12:52:20 +02:00
ArrangeElement(element, viewportPosition);
2012-04-25 22:02:53 +02:00
}
private static bool ArrangeElement(UIElement element, Point position)
{
Rect rect = new Rect(position, element.DesiredSize);
FrameworkElement frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
if (frameworkElement.HorizontalAlignment == HorizontalAlignment.Stretch &&
frameworkElement.VerticalAlignment == VerticalAlignment.Stretch)
{
return false; // do not arrange at position
}
switch (frameworkElement.HorizontalAlignment)
{
case HorizontalAlignment.Center:
rect.X -= rect.Width / 2d;
break;
case HorizontalAlignment.Right:
rect.X -= rect.Width;
break;
default:
break;
}
switch (frameworkElement.VerticalAlignment)
{
case VerticalAlignment.Center:
rect.Y -= rect.Height / 2d;
break;
case VerticalAlignment.Bottom:
rect.Y -= rect.Height;
break;
default:
break;
}
}
element.Arrange(rect);
return true;
}
private static void ArrangeElement(UIElement element, Size panelSize)
{
Rect rect = new Rect(element.DesiredSize);
FrameworkElement frameworkElement = element as FrameworkElement;
if (frameworkElement != null)
{
switch (frameworkElement.HorizontalAlignment)
{
case HorizontalAlignment.Center:
rect.X = (panelSize.Width - rect.Width) / 2d;
break;
case HorizontalAlignment.Right:
rect.X = panelSize.Width - rect.Width;
break;
case HorizontalAlignment.Stretch:
rect.Width = panelSize.Width;
break;
default:
break;
}
switch (frameworkElement.VerticalAlignment)
{
case VerticalAlignment.Center:
rect.Y = (panelSize.Height - rect.Height) / 2d;
break;
case VerticalAlignment.Bottom:
rect.Y = panelSize.Height - rect.Height;
break;
case VerticalAlignment.Stretch:
rect.Height = panelSize.Height;
break;
default:
break;
}
}
element.Arrange(rect);
}
}
}