mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
254 lines
8.9 KiB
C#
254 lines
8.9 KiB
C#
|
|
using System;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Media;
|
|||
|
|
|
|||
|
|
namespace MapControl
|
|||
|
|
{
|
|||
|
|
public class MapPanel : Panel, INotifyParentMapChanged
|
|||
|
|
{
|
|||
|
|
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(
|
|||
|
|
"Location", typeof(Point?), typeof(MapPanel),
|
|||
|
|
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, LocationPropertyChanged));
|
|||
|
|
|
|||
|
|
internal static readonly DependencyPropertyKey ViewPositionPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
|||
|
|
"ViewPosition", typeof(Point), typeof(MapPanel), null);
|
|||
|
|
|
|||
|
|
private static readonly DependencyPropertyKey ViewPositionTransformPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
|||
|
|
"ViewPositionTransform", typeof(Transform), typeof(MapPanel), null);
|
|||
|
|
|
|||
|
|
public static readonly DependencyProperty ViewPositionProperty = ViewPositionPropertyKey.DependencyProperty;
|
|||
|
|
public static readonly DependencyProperty ViewPositionTransformProperty = ViewPositionTransformPropertyKey.DependencyProperty;
|
|||
|
|
|
|||
|
|
public MapPanel()
|
|||
|
|
{
|
|||
|
|
ClipToBounds = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public Map ParentMap
|
|||
|
|
{
|
|||
|
|
get { return (Map)GetValue(ParentMapProperty); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static Map GetParentMap(UIElement element)
|
|||
|
|
{
|
|||
|
|
return (Map)element.GetValue(ParentMapProperty);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static Point? GetLocation(UIElement element)
|
|||
|
|
{
|
|||
|
|
return (Point?)element.GetValue(LocationProperty);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static void SetLocation(UIElement element, Point? value)
|
|||
|
|
{
|
|||
|
|
element.SetValue(LocationProperty, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static Point GetViewPosition(UIElement element)
|
|||
|
|
{
|
|||
|
|
return (Point)element.GetValue(ViewPositionProperty);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static Transform GetViewPositionTransform(UIElement element)
|
|||
|
|
{
|
|||
|
|
return (Transform)element.GetValue(ViewPositionTransformProperty);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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)
|
|||
|
|
{
|
|||
|
|
object viewPosition = element.ReadLocalValue(ViewPositionProperty);
|
|||
|
|
|
|||
|
|
if (viewPosition == DependencyProperty.UnsetValue ||
|
|||
|
|
!ArrangeElement(element, (Point)viewPosition))
|
|||
|
|
{
|
|||
|
|
ArrangeElement(element, finalSize);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return finalSize;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected virtual void OnViewTransformChanged(Map parentMap)
|
|||
|
|
{
|
|||
|
|
foreach (UIElement element in InternalChildren)
|
|||
|
|
{
|
|||
|
|
Point? location = GetLocation(element);
|
|||
|
|
|
|||
|
|
if (location.HasValue)
|
|||
|
|
{
|
|||
|
|
SetViewPosition(element, parentMap, location);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnViewTransformChanged(object sender, EventArgs eventArgs)
|
|||
|
|
{
|
|||
|
|
OnViewTransformChanged((Map)sender);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void INotifyParentMapChanged.ParentMapChanged(Map oldParentMap, Map newParentMap)
|
|||
|
|
{
|
|||
|
|
if (oldParentMap != null && oldParentMap != this)
|
|||
|
|
{
|
|||
|
|
oldParentMap.ViewTransformChanged -= OnViewTransformChanged;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (newParentMap != null && newParentMap != this)
|
|||
|
|
{
|
|||
|
|
newParentMap.ViewTransformChanged += OnViewTransformChanged;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
|
|||
|
|
{
|
|||
|
|
INotifyParentMapChanged notifyChanged = obj as INotifyParentMapChanged;
|
|||
|
|
|
|||
|
|
if (notifyChanged != null)
|
|||
|
|
{
|
|||
|
|
notifyChanged.ParentMapChanged(eventArgs.OldValue as Map, eventArgs.NewValue as Map);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
|
|||
|
|
{
|
|||
|
|
UIElement element = (UIElement)obj;
|
|||
|
|
Point? location = (Point?)eventArgs.NewValue;
|
|||
|
|
Map parentMap;
|
|||
|
|
|
|||
|
|
if (location.HasValue && (parentMap = Map.GetParentMap(element)) != null)
|
|||
|
|
{
|
|||
|
|
SetViewPosition(element, parentMap, location);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
element.ClearValue(ViewPositionPropertyKey);
|
|||
|
|
element.ClearValue(ViewPositionTransformPropertyKey);
|
|||
|
|
element.Arrange(new Rect());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static void SetViewPosition(UIElement element, Map parentMap, Point? location)
|
|||
|
|
{
|
|||
|
|
Point viewPosition = parentMap.MapViewTransform.Transform(location.Value);
|
|||
|
|
|
|||
|
|
element.SetValue(ViewPositionPropertyKey, viewPosition);
|
|||
|
|
|
|||
|
|
Matrix matrix = new Matrix(1d, 0d, 0d, 1d, viewPosition.X, viewPosition.Y);
|
|||
|
|
MatrixTransform viewTransform = element.GetValue(ViewPositionTransformProperty) as MatrixTransform;
|
|||
|
|
|
|||
|
|
if (viewTransform != null)
|
|||
|
|
{
|
|||
|
|
viewTransform.Matrix = matrix;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
element.SetValue(ViewPositionTransformPropertyKey, new MatrixTransform(matrix));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ArrangeElement(element, viewPosition);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|