Version 1.2.0: Added classes MapShape, MapRectangle and MapImage.

This commit is contained in:
ClemensF 2013-04-12 19:59:16 +02:00
parent ec27d16119
commit 9b218ef376
45 changed files with 846 additions and 565 deletions

View file

@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -22,7 +22,7 @@ namespace MapControl
private const FillBehavior AnimationFillBehavior = FillBehavior.HoldEnd; private const FillBehavior AnimationFillBehavior = FillBehavior.HoldEnd;
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register( public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
"Foreground", typeof(Brush), typeof(MapBase), null); "Foreground", typeof(Brush), typeof(MapBase), new PropertyMetadata(new SolidColorBrush(Colors.Black)));
partial void Initialize() partial void Initialize()
{ {

View file

@ -108,7 +108,7 @@ namespace MapControl
public MapBase() public MapBase()
{ {
SetValue(MapPanel.ParentMapProperty, this); SetParentMap();
Background = LightBackground; Background = LightBackground;
TileLayers = new TileLayerCollection(); TileLayers = new TileLayerCollection();

View file

@ -75,15 +75,17 @@
<Compile Include="MapBase.Silverlight.WinRT.cs" /> <Compile Include="MapBase.Silverlight.WinRT.cs" />
<Compile Include="MapGraticule.cs" /> <Compile Include="MapGraticule.cs" />
<Compile Include="MapGraticule.Silverlight.WinRT.cs" /> <Compile Include="MapGraticule.Silverlight.WinRT.cs" />
<Compile Include="MapImage.cs" />
<Compile Include="MapItem.Silverlight.WinRT.cs" /> <Compile Include="MapItem.Silverlight.WinRT.cs" />
<Compile Include="MapItemsControl.cs" /> <Compile Include="MapItemsControl.cs" />
<Compile Include="MapItemsControl.Silverlight.WinRT.cs" /> <Compile Include="MapItemsControl.Silverlight.WinRT.cs" />
<Compile Include="MapOverlay.cs" />
<Compile Include="MapOverlay.Silverlight.WinRT.cs" />
<Compile Include="MapPanel.cs" /> <Compile Include="MapPanel.cs" />
<Compile Include="MapPanel.Silverlight.WinRT.cs" /> <Compile Include="MapPanel.Silverlight.WinRT.cs" />
<Compile Include="MapRectangle.cs" />
<Compile Include="MapShape.cs" />
<Compile Include="MapPolyline.cs" /> <Compile Include="MapPolyline.cs" />
<Compile Include="MapPolyline.Silverlight.WinRT.cs" /> <Compile Include="MapPolyline.Silverlight.WinRT.cs" />
<Compile Include="MapShape.Silverlight.WinRT.cs" />
<Compile Include="MapTransform.cs" /> <Compile Include="MapTransform.cs" />
<Compile Include="MatrixEx.cs" /> <Compile Include="MatrixEx.cs" />
<Compile Include="MercatorTransform.cs" /> <Compile Include="MercatorTransform.cs" />

View file

@ -46,7 +46,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="MapGraticule.WPF.cs" /> <Compile Include="MapGraticule.WPF.cs" />
<Compile Include="MapOverlay.WPF.cs" />
<Compile Include="Location.cs" /> <Compile Include="Location.cs" />
<Compile Include="LocationCollection.cs" /> <Compile Include="LocationCollection.cs" />
<Compile Include="LocationCollectionConverter.cs" /> <Compile Include="LocationCollectionConverter.cs" />
@ -60,10 +59,14 @@
<Compile Include="MapItem.WPF.cs" /> <Compile Include="MapItem.WPF.cs" />
<Compile Include="MapItemsControl.cs" /> <Compile Include="MapItemsControl.cs" />
<Compile Include="MapItemsControl.WPF.cs" /> <Compile Include="MapItemsControl.WPF.cs" />
<Compile Include="MapImage.cs" />
<Compile Include="MapPanel.cs" /> <Compile Include="MapPanel.cs" />
<Compile Include="MapPanel.WPF.cs" /> <Compile Include="MapPanel.WPF.cs" />
<Compile Include="MapPolyline.cs" /> <Compile Include="MapPolyline.cs" />
<Compile Include="MapPolyline.WPF.cs" /> <Compile Include="MapPolyline.WPF.cs" />
<Compile Include="MapRectangle.cs" />
<Compile Include="MapShape.cs" />
<Compile Include="MapShape.WPF.cs" />
<Compile Include="MapTransform.cs" /> <Compile Include="MapTransform.cs" />
<Compile Include="MercatorTransform.cs" /> <Compile Include="MercatorTransform.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -6,97 +6,219 @@ using System;
using System.Linq; using System.Linq;
#if NETFX_CORE #if NETFX_CORE
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Data;
#else #else
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Data;
#endif #endif
namespace MapControl namespace MapControl
{ {
public partial class MapGraticule public partial class MapGraticule : MapPanel
{ {
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
"FontFamily", typeof(FontFamily), typeof(MapGraticule),
new PropertyMetadata(default(FontFamily), (o, e) => ((MapGraticule)o).OnViewportChanged()));
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
"FontSize", typeof(double), typeof(MapGraticule),
new PropertyMetadata(10d, (o, e) => ((MapGraticule)o).OnViewportChanged()));
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
"FontStyle", typeof(FontStyle), typeof(MapGraticule),
new PropertyMetadata(default(FontStyle), (o, e) => ((MapGraticule)o).OnViewportChanged()));
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
"FontStretch", typeof(FontStretch), typeof(MapGraticule),
new PropertyMetadata(default(FontStretch), (o, e) => ((MapGraticule)o).OnViewportChanged()));
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
"FontWeight", typeof(FontWeight), typeof(MapGraticule),
new PropertyMetadata(FontWeights.Normal, (o, e) => ((MapGraticule)o).OnViewportChanged()));
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
"Foreground", typeof(Brush), typeof(MapGraticule),
new PropertyMetadata(null, (o, e) => ((MapGraticule)o).OnViewportChanged()));
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
"Stroke", typeof(Brush), typeof(MapGraticule),
new PropertyMetadata(null, (o, e) => ((MapGraticule)o).path.Stroke = (Brush)e.NewValue));
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
"StrokeThickness", typeof(double), typeof(MapGraticule),
new PropertyMetadata(0.5, (o, e) => ((MapGraticule)o).path.StrokeThickness = (double)e.NewValue));
private readonly Path path;
private Location graticuleStart; private Location graticuleStart;
private Location graticuleEnd; private Location graticuleEnd;
public MapGraticule()
{
IsHitTestVisible = false;
path = new Path
{
Stroke = Stroke,
StrokeThickness = StrokeThickness
};
Children.Add(path);
}
public FontFamily FontFamily
{
get { return (FontFamily)GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
public double FontSize
{
get { return (double)GetValue(FontSizeProperty); }
set { SetValue(FontSizeProperty, value); }
}
public FontStyle FontStyle
{
get { return (FontStyle)GetValue(FontStyleProperty); }
set { SetValue(FontStyleProperty, value); }
}
public FontStretch FontStretch
{
get { return (FontStretch)GetValue(FontStretchProperty); }
set { SetValue(FontStretchProperty, value); }
}
public FontWeight FontWeight
{
get { return (FontWeight)GetValue(FontWeightProperty); }
set { SetValue(FontWeightProperty, value); }
}
public Brush Foreground
{
get { return (Brush)GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
public Brush Stroke
{
get { return (Brush)GetValue(StrokeProperty); }
set { SetValue(StrokeProperty, value); }
}
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
protected override void OnViewportChanged() protected override void OnViewportChanged()
{ {
var parentMap = MapPanel.GetParentMap(this); if (ParentMap != null)
var bounds = parentMap.ViewportTransform.Inverse.TransformBounds(new Rect(0d, 0d, parentMap.RenderSize.Width, parentMap.RenderSize.Height));
var start = parentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
var end = parentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, parentMap.ZoomLevel) * 256d);
var spacing = LineSpacings[LineSpacings.Length - 1];
if (spacing >= minSpacing)
{ {
spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing); if (path.Data == null)
}
var labelsStart = new Location(
Math.Ceiling(start.Latitude / spacing) * spacing,
Math.Ceiling(start.Longitude / spacing) * spacing);
var labelsEnd = new Location(
Math.Floor(end.Latitude / spacing) * spacing,
Math.Floor(end.Longitude / spacing) * spacing);
var linesStart = new Location(
Math.Min(Math.Max(labelsStart.Latitude - spacing, -parentMap.MapTransform.MaxLatitude), parentMap.MapTransform.MaxLatitude),
labelsStart.Longitude - spacing);
var linesEnd = new Location(
Math.Min(Math.Max(labelsEnd.Latitude + spacing, -parentMap.MapTransform.MaxLatitude), parentMap.MapTransform.MaxLatitude),
labelsEnd.Longitude + spacing);
if (!linesStart.Equals(graticuleStart) || !linesEnd.Equals(graticuleEnd))
{
graticuleStart = linesStart;
graticuleEnd = linesEnd;
Geometry.Figures.Clear();
Geometry.Transform = parentMap.ViewportTransform;
for (var lat = labelsStart.Latitude; lat <= end.Latitude; lat += spacing)
{ {
var figure = new PathFigure path.Data = new PathGeometry();
{
StartPoint = parentMap.MapTransform.Transform(new Location(lat, linesStart.Longitude)),
IsClosed = false,
IsFilled = false
};
figure.Segments.Add(new LineSegment if (Foreground == null)
{ {
Point = parentMap.MapTransform.Transform(new Location(lat, linesEnd.Longitude)), SetBinding(ForegroundProperty, new Binding()
}); {
Source = ParentMap,
Path = new PropertyPath("Foreground")
});
}
Geometry.Figures.Add(figure); if (Stroke == null)
{
SetBinding(StrokeProperty, new Binding()
{
Source = ParentMap,
Path = new PropertyPath("Foreground")
});
}
} }
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing) var geometry = (PathGeometry)path.Data;
var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(0d, 0d, ParentMap.RenderSize.Width, ParentMap.RenderSize.Height));
var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * 256d);
var spacing = LineSpacings[LineSpacings.Length - 1];
if (spacing >= minSpacing)
{ {
var figure = new PathFigure spacing = LineSpacings.FirstOrDefault(s => s >= minSpacing);
{
StartPoint = parentMap.MapTransform.Transform(new Location(linesStart.Latitude, lon)),
IsClosed = false,
IsFilled = false
};
figure.Segments.Add(new LineSegment
{
Point = parentMap.MapTransform.Transform(new Location(linesEnd.Latitude, lon)),
});
Geometry.Figures.Add(figure);
} }
var childIndex = 1; // 0 for Path var labelsStart = new Location(
Math.Ceiling(start.Latitude / spacing) * spacing,
Math.Ceiling(start.Longitude / spacing) * spacing);
if (Foreground != null) var labelsEnd = new Location(
Math.Floor(end.Latitude / spacing) * spacing,
Math.Floor(end.Longitude / spacing) * spacing);
var linesStart = new Location(
Math.Min(Math.Max(labelsStart.Latitude - spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
labelsStart.Longitude - spacing);
var linesEnd = new Location(
Math.Min(Math.Max(labelsEnd.Latitude + spacing, -ParentMap.MapTransform.MaxLatitude), ParentMap.MapTransform.MaxLatitude),
labelsEnd.Longitude + spacing);
if (!linesStart.Equals(graticuleStart) || !linesEnd.Equals(graticuleEnd))
{ {
graticuleStart = linesStart;
graticuleEnd = linesEnd;
geometry.Figures.Clear();
geometry.Transform = ParentMap.ViewportTransform;
for (var lat = labelsStart.Latitude; lat <= end.Latitude; lat += spacing)
{
var figure = new PathFigure
{
StartPoint = ParentMap.MapTransform.Transform(new Location(lat, linesStart.Longitude)),
IsClosed = false,
IsFilled = false
};
figure.Segments.Add(new LineSegment
{
Point = ParentMap.MapTransform.Transform(new Location(lat, linesEnd.Longitude)),
});
geometry.Figures.Add(figure);
}
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing)
{
var figure = new PathFigure
{
StartPoint = ParentMap.MapTransform.Transform(new Location(linesStart.Latitude, lon)),
IsClosed = false,
IsFilled = false
};
figure.Segments.Add(new LineSegment
{
Point = ParentMap.MapTransform.Transform(new Location(linesEnd.Latitude, lon)),
});
geometry.Figures.Add(figure);
}
var childIndex = 1; // 0 for Path
var format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°"; var format = spacing < 1d ? "{0} {1}°{2:00}'" : "{0} {1}°";
var measureSize = new Size(double.PositiveInfinity, double.PositiveInfinity); var measureSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
@ -113,7 +235,17 @@ namespace MapControl
} }
else else
{ {
label = new TextBlock { RenderTransform = new TransformGroup() }; label = new TextBlock
{
RenderTransform = new TransformGroup()
};
label.SetBinding(TextBlock.ForegroundProperty, new Binding
{
Source = this,
Path = new PropertyPath("Foreground")
});
Children.Add(label); Children.Add(label);
} }
@ -126,9 +258,8 @@ namespace MapControl
label.FontSize = FontSize; label.FontSize = FontSize;
label.FontStyle = FontStyle; label.FontStyle = FontStyle;
label.FontWeight = FontWeight;
label.FontStretch = FontStretch; label.FontStretch = FontStretch;
label.Foreground = Foreground; label.FontWeight = FontWeight;
label.Text = string.Format("{0}\n{1}", label.Text = string.Format("{0}\n{1}",
CoordinateString(lat, format, "NS"), CoordinateString(lat, format, "NS"),
@ -141,7 +272,7 @@ namespace MapControl
if (transformGroup.Children.Count == 0) if (transformGroup.Children.Count == 0)
{ {
transformGroup.Children.Add(new TranslateTransform()); transformGroup.Children.Add(new TranslateTransform());
transformGroup.Children.Add(parentMap.RotateTransform); transformGroup.Children.Add(ParentMap.RotateTransform);
} }
var translateTransform = (TranslateTransform)transformGroup.Children[0]; var translateTransform = (TranslateTransform)transformGroup.Children[0];
@ -151,13 +282,17 @@ namespace MapControl
MapPanel.SetLocation(label, location); MapPanel.SetLocation(label, location);
} }
} }
}
while (Children.Count > childIndex) while (Children.Count > childIndex)
{ {
Children.RemoveAt(Children.Count - 1); Children.RemoveAt(Children.Count - 1);
}
} }
} }
else
{
path.Data = null;
}
base.OnViewportChanged(); base.OnViewportChanged();
} }

View file

@ -9,18 +9,30 @@ using System.Windows.Media;
namespace MapControl namespace MapControl
{ {
public partial class MapGraticule public partial class MapGraticule : MapOverlay
{ {
static MapGraticule()
{
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
typeof(MapGraticule), new FrameworkPropertyMetadata(false));
MapOverlay.StrokeThicknessProperty.OverrideMetadata(
typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
}
protected override void OnViewportChanged()
{
InvalidateVisual();
}
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
{ {
var parentMap = MapPanel.GetParentMap(this); if (ParentMap != null)
if (parentMap != null)
{ {
var bounds = parentMap.ViewportTransform.Inverse.TransformBounds(new Rect(parentMap.RenderSize)); var bounds = ParentMap.ViewportTransform.Inverse.TransformBounds(new Rect(ParentMap.RenderSize));
var start = parentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y)); var start = ParentMap.MapTransform.Transform(new Point(bounds.X, bounds.Y));
var end = parentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height)); var end = ParentMap.MapTransform.Transform(new Point(bounds.X + bounds.Width, bounds.Y + bounds.Height));
var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, parentMap.ZoomLevel) * 256d); var minSpacing = MinLineSpacing * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * 256d);
var spacing = LineSpacings[LineSpacings.Length - 1]; var spacing = LineSpacings[LineSpacings.Length - 1];
if (spacing >= minSpacing) if (spacing >= minSpacing)
@ -35,15 +47,15 @@ namespace MapControl
for (var lat = labelsStart.Latitude; lat <= end.Latitude; lat += spacing) for (var lat = labelsStart.Latitude; lat <= end.Latitude; lat += spacing)
{ {
drawingContext.DrawLine(Pen, drawingContext.DrawLine(Pen,
parentMap.LocationToViewportPoint(new Location(lat, start.Longitude)), ParentMap.LocationToViewportPoint(new Location(lat, start.Longitude)),
parentMap.LocationToViewportPoint(new Location(lat, end.Longitude))); ParentMap.LocationToViewportPoint(new Location(lat, end.Longitude)));
} }
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing) for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing)
{ {
drawingContext.DrawLine(Pen, drawingContext.DrawLine(Pen,
parentMap.LocationToViewportPoint(new Location(start.Latitude, lon)), ParentMap.LocationToViewportPoint(new Location(start.Latitude, lon)),
parentMap.LocationToViewportPoint(new Location(end.Latitude, lon))); ParentMap.LocationToViewportPoint(new Location(end.Latitude, lon)));
} }
if (Foreground != null && Foreground != Brushes.Transparent) if (Foreground != null && Foreground != Brushes.Transparent)
@ -55,13 +67,13 @@ namespace MapControl
for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing) for (var lon = labelsStart.Longitude; lon <= end.Longitude; lon += spacing)
{ {
var t = StrokeThickness / 2d; var t = StrokeThickness / 2d;
var p = parentMap.LocationToViewportPoint(new Location(lat, lon)); var p = ParentMap.LocationToViewportPoint(new Location(lat, lon));
var latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d); var latPos = new Point(p.X + t + 2d, p.Y - t - FontSize / 4d);
var lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize); var lonPos = new Point(p.X + t + 2d, p.Y + t + FontSize);
var latLabel = CoordinateString(lat, format, "NS"); var latLabel = CoordinateString(lat, format, "NS");
var lonLabel = CoordinateString(Location.NormalizeLongitude(lon), format, "EW"); var lonLabel = CoordinateString(Location.NormalizeLongitude(lon), format, "EW");
drawingContext.PushTransform(new RotateTransform(parentMap.Heading, p.X, p.Y)); drawingContext.PushTransform(new RotateTransform(ParentMap.Heading, p.X, p.Y));
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(latLabel, Typeface, FontSize, latPos)); drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(latLabel, Typeface, FontSize, latPos));
drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(lonLabel, Typeface, FontSize, lonPos)); drawingContext.DrawGlyphRun(Foreground, GlyphRunText.Create(lonLabel, Typeface, FontSize, lonPos));
drawingContext.Pop(); drawingContext.Pop();

View file

@ -13,7 +13,7 @@ namespace MapControl
/// <summary> /// <summary>
/// Draws a graticule overlay. /// Draws a graticule overlay.
/// </summary> /// </summary>
public partial class MapGraticule : MapOverlay public partial class MapGraticule
{ {
/// <summary> /// <summary>
/// Graticule line spacings in degrees. /// Graticule line spacings in degrees.
@ -24,11 +24,6 @@ namespace MapControl
public static readonly DependencyProperty MinLineSpacingProperty = DependencyProperty.Register( public static readonly DependencyProperty MinLineSpacingProperty = DependencyProperty.Register(
"MinLineSpacing", typeof(double), typeof(MapGraticule), new PropertyMetadata(150d)); "MinLineSpacing", typeof(double), typeof(MapGraticule), new PropertyMetadata(150d));
public MapGraticule()
{
StrokeThickness = 0.5;
}
/// <summary> /// <summary>
/// Minimum spacing in pixels between adjacent graticule lines. /// Minimum spacing in pixels between adjacent graticule lines.
/// </summary> /// </summary>

41
MapControl/MapImage.cs Normal file
View file

@ -0,0 +1,41 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl
{
public class MapImage : MapRectangle
{
private static readonly Transform imageTransform = new MatrixTransform
{
Matrix = new Matrix(1, 0, 0, -1, 0, 1)
};
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
"Source", typeof(ImageSource), typeof(MapImage),
new PropertyMetadata(null, (o, e) => ((MapImage)o).SourceChanged((ImageSource)e.NewValue)));
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
private void SourceChanged(ImageSource source)
{
Fill = new ImageBrush
{
ImageSource = source,
RelativeTransform = imageTransform
};
}
}
}

View file

@ -15,8 +15,7 @@ namespace MapControl
public class MapItem : ListBoxItem public class MapItem : ListBoxItem
{ {
public static readonly DependencyProperty IsCurrentProperty = MapItemsControl.IsCurrentProperty.AddOwner( public static readonly DependencyProperty IsCurrentProperty = MapItemsControl.IsCurrentProperty.AddOwner(
typeof(MapItem), typeof(MapItem), new PropertyMetadata((o, e) => ((MapItem)o).IsCurrentPropertyChanged((bool)e.NewValue)));
new PropertyMetadata((o, e) => ((MapItem)o).IsCurrentPropertyChanged((bool)e.NewValue)));
static MapItem() static MapItem()
{ {

View file

@ -1,129 +0,0 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
#else
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
#endif
namespace MapControl
{
public partial class MapOverlay : MapPanel
{
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
"FontFamily", typeof(FontFamily), typeof(MapOverlay),
new PropertyMetadata(default(FontFamily), (o, e) => ((MapOverlay)o).FontSizePropertyChanged()));
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
"FontSize", typeof(double), typeof(MapOverlay),
new PropertyMetadata(10d, (o, e) => ((MapOverlay)o).FontSizePropertyChanged()));
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
"FontStyle", typeof(FontStyle), typeof(MapOverlay),
new PropertyMetadata(default(FontStyle), (o, e) => ((MapOverlay)o).FontSizePropertyChanged()));
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
"FontStretch", typeof(FontStretch), typeof(MapOverlay),
new PropertyMetadata(default(FontStretch), (o, e) => ((MapOverlay)o).FontSizePropertyChanged()));
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
"FontWeight", typeof(FontWeight), typeof(MapOverlay),
new PropertyMetadata(FontWeights.Normal, (o, e) => ((MapOverlay)o).FontSizePropertyChanged()));
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
"Foreground", typeof(Brush), typeof(MapOverlay),
new PropertyMetadata(new SolidColorBrush(Colors.Black), (o, e) => ((MapOverlay)o).ForegroundPropertyChanged()));
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
"Stroke", typeof(Brush), typeof(MapOverlay),
new PropertyMetadata(new SolidColorBrush(Colors.Black), (o, e) => ((MapOverlay)o).Path.Stroke = (Brush)e.NewValue));
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
"StrokeThickness", typeof(double), typeof(MapOverlay),
new PropertyMetadata(1d, (o, e) => ((MapOverlay)o).StrokeThicknessPropertyChanged((double)e.NewValue)));
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
"StrokeDashArray", typeof(DoubleCollection), typeof(MapOverlay),
new PropertyMetadata(null, (o, e) => ((MapOverlay)o).Path.StrokeDashArray = (DoubleCollection)e.NewValue));
public static readonly DependencyProperty StrokeDashOffsetProperty = DependencyProperty.Register(
"StrokeDashOffset", typeof(double), typeof(MapOverlay),
new PropertyMetadata(0d, (o, e) => ((MapOverlay)o).Path.StrokeDashOffset = (double)e.NewValue));
public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register(
"StrokeDashCap", typeof(PenLineCap), typeof(MapOverlay),
new PropertyMetadata(default(PenLineCap), (o, e) => ((MapOverlay)o).Path.StrokeDashCap = (PenLineCap)e.NewValue));
public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register(
"StrokeStartLineCap", typeof(PenLineCap), typeof(MapOverlay),
new PropertyMetadata(default(PenLineCap), (o, e) => ((MapOverlay)o).Path.StrokeStartLineCap = (PenLineCap)e.NewValue));
public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register(
"StrokeEndLineCap", typeof(PenLineCap), typeof(MapOverlay),
new PropertyMetadata(default(PenLineCap), (o, e) => ((MapOverlay)o).Path.StrokeEndLineCap = (PenLineCap)e.NewValue));
public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register(
"StrokeLineJoin", typeof(PenLineJoin), typeof(MapOverlay),
new PropertyMetadata(default(PenLineJoin), (o, e) => ((MapOverlay)o).Path.StrokeLineJoin = (PenLineJoin)e.NewValue));
public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register(
"StrokeMiterLimit", typeof(double), typeof(MapOverlay),
new PropertyMetadata(1d, (o, e) => ((MapOverlay)o).Path.StrokeMiterLimit = (double)e.NewValue));
protected readonly Path Path = new Path();
protected readonly PathGeometry Geometry = new PathGeometry();
public MapOverlay()
{
IsHitTestVisible = false;
Path.Stroke = Stroke;
Path.StrokeThickness = StrokeThickness;
Path.StrokeDashArray = StrokeDashArray;
Path.StrokeDashOffset = StrokeDashOffset;
Path.StrokeDashCap = StrokeDashCap;
Path.StrokeStartLineCap = StrokeStartLineCap;
Path.StrokeEndLineCap = StrokeEndLineCap;
Path.StrokeLineJoin = StrokeLineJoin;
Path.StrokeMiterLimit = StrokeMiterLimit;
Path.Data = Geometry;
Children.Add(Path);
}
private void FontSizePropertyChanged()
{
if (GetParentMap(this) != null)
{
// FontSize may affect layout
OnViewportChanged();
}
}
private void ForegroundPropertyChanged()
{
if (GetParentMap(this) != null)
{
// Foreground may affect rendering
OnViewportChanged();
}
}
private void StrokeThicknessPropertyChanged(double thickness)
{
Path.StrokeThickness = thickness;
if (GetParentMap(this) != null)
{
// StrokeThickness may affect layout
OnViewportChanged();
}
}
}
}

View file

@ -1,151 +0,0 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace MapControl
{
public partial class MapOverlay : FrameworkElement, IMapElement
{
public static readonly DependencyProperty BackgroundProperty = Control.BackgroundProperty.AddOwner(
typeof(MapOverlay));
public static readonly DependencyProperty FontSizeProperty = Control.FontSizeProperty.AddOwner(
typeof(MapOverlay));
public static readonly DependencyProperty FontFamilyProperty = Control.FontFamilyProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty FontStyleProperty = Control.FontStyleProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty FontStretchProperty = Control.FontStretchProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty FontWeightProperty = Control.FontWeightProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).ForegroundChanged((Brush)e.NewValue)));
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.Brush = (Brush)e.NewValue));
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsMeasure, (o, e) => ((MapOverlay)o).pen.Thickness = (double)e.NewValue));
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.DashStyle = new DashStyle((DoubleCollection)e.NewValue, ((MapOverlay)o).StrokeDashOffset)));
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.DashStyle = new DashStyle(((MapOverlay)o).StrokeDashArray, (double)e.NewValue)));
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.DashCap = (PenLineCap)e.NewValue));
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.StartLineCap = (PenLineCap)e.NewValue));
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.EndLineCap = (PenLineCap)e.NewValue));
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.LineJoin = (PenLineJoin)e.NewValue));
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen.MiterLimit = (double)e.NewValue));
private Pen pen;
private Typeface typeface;
static MapOverlay()
{
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
typeof(MapOverlay), new FrameworkPropertyMetadata(false));
}
public MapOverlay()
{
pen = new Pen
{
Brush = Stroke,
Thickness = StrokeThickness,
DashStyle = new DashStyle(StrokeDashArray, StrokeDashOffset),
DashCap = StrokeDashCap,
StartLineCap = StrokeStartLineCap,
EndLineCap = StrokeEndLineCap,
LineJoin = StrokeLineJoin,
MiterLimit = StrokeMiterLimit
};
}
public Brush Background
{
get { return (Brush)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
protected Pen Pen
{
get
{
if (pen.Brush == null)
{
pen.Brush = Foreground;
}
return pen;
}
}
protected Typeface Typeface
{
get
{
if (typeface == null)
{
typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
}
return typeface;
}
}
protected virtual void OnViewportChanged()
{
InvalidateVisual();
}
private void OnViewportChanged(object sender, EventArgs e)
{
OnViewportChanged();
}
void IMapElement.ParentMapChanged(MapBase oldParentMap, MapBase newParentMap)
{
if (oldParentMap != null)
{
oldParentMap.ViewportChanged -= OnViewportChanged;
}
if (newParentMap != null)
{
newParentMap.ViewportChanged += OnViewportChanged;
OnViewportChanged();
}
}
private void ForegroundChanged(Brush foreground)
{
if (Stroke == null)
{
pen.Brush = foreground;
}
}
}
}

View file

@ -2,26 +2,70 @@
// Copyright © 2013 Clemens Fischer // Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Text;
using Windows.UI.Xaml.Media;
#else
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
#endif using System.Windows.Shapes;
namespace MapControl namespace MapControl
{ {
/// <summary> /// <summary>
/// Base class for map overlays with font, background, foreground and stroke properties. /// Base class for map overlays with font, background, foreground and stroke properties.
/// Rendering is typically done by overriding OnRender in derived classes.
/// </summary> /// </summary>
public partial class MapOverlay public class MapOverlay : FrameworkElement, IMapElement
{ {
public FontFamily FontFamily public static readonly DependencyProperty FontSizeProperty = Control.FontSizeProperty.AddOwner(
{ typeof(MapOverlay));
get { return (FontFamily)GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); } public static readonly DependencyProperty FontFamilyProperty = Control.FontFamilyProperty.AddOwner(
} typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty FontStyleProperty = Control.FontStyleProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty FontStretchProperty = Control.FontStretchProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty FontWeightProperty = Control.FontWeightProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).typeface = null));
public static readonly DependencyProperty BackgroundProperty = Control.BackgroundProperty.AddOwner(
typeof(MapOverlay));
public static readonly DependencyProperty ForegroundProperty = Control.ForegroundProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).ForegroundChanged()));
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(default(PenLineCap), FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(default(PenLineCap), FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(default(PenLineCap), FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(default(PenLineJoin), FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((MapOverlay)o).pen = null));
private MapBase parentMap;
private Typeface typeface;
private Pen pen;
public double FontSize public double FontSize
{ {
@ -29,6 +73,12 @@ namespace MapControl
set { SetValue(FontSizeProperty, value); } set { SetValue(FontSizeProperty, value); }
} }
public FontFamily FontFamily
{
get { return (FontFamily)GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
public FontStyle FontStyle public FontStyle FontStyle
{ {
get { return (FontStyle)GetValue(FontStyleProperty); } get { return (FontStyle)GetValue(FontStyleProperty); }
@ -47,6 +97,12 @@ namespace MapControl
set { SetValue(FontWeightProperty, value); } set { SetValue(FontWeightProperty, value); }
} }
public Brush Background
{
get { return (Brush)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
public Brush Foreground public Brush Foreground
{ {
get { return (Brush)GetValue(ForegroundProperty); } get { return (Brush)GetValue(ForegroundProperty); }
@ -106,5 +162,75 @@ namespace MapControl
get { return (double)GetValue(StrokeMiterLimitProperty); } get { return (double)GetValue(StrokeMiterLimitProperty); }
set { SetValue(StrokeMiterLimitProperty, value); } set { SetValue(StrokeMiterLimitProperty, value); }
} }
public MapBase ParentMap
{
get { return parentMap; }
set
{
if (parentMap != null)
{
parentMap.ViewportChanged -= (o, e) => OnViewportChanged();
}
parentMap = value;
if (parentMap != null)
{
parentMap.ViewportChanged += (o, e) => OnViewportChanged();
OnViewportChanged();
}
}
}
protected Typeface Typeface
{
get
{
if (typeface == null)
{
typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
}
return typeface;
}
}
protected Pen Pen
{
get
{
if (pen == null)
{
pen = new Pen
{
Brush = Stroke != null ? Stroke : Foreground,
Thickness = StrokeThickness,
DashStyle = new DashStyle(StrokeDashArray, StrokeDashOffset),
DashCap = StrokeDashCap,
StartLineCap = StrokeStartLineCap,
EndLineCap = StrokeEndLineCap,
LineJoin = StrokeLineJoin,
MiterLimit = StrokeMiterLimit
};
pen.Freeze();
}
return pen;
}
}
protected virtual void OnViewportChanged()
{
}
private void ForegroundChanged()
{
if (Stroke == null)
{
pen = null;
}
}
} }
} }

View file

@ -72,5 +72,10 @@ namespace MapControl
return parentMap; return parentMap;
} }
internal void SetParentMap()
{
SetValue(ParentMapProperty, this);
}
} }
} }

View file

@ -8,13 +8,20 @@ namespace MapControl
{ {
public partial class MapPanel public partial class MapPanel
{ {
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached( private static readonly DependencyPropertyKey ParentMapPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
"ParentMap", typeof(MapBase), typeof(MapPanel), "ParentMap", typeof(MapBase), typeof(MapPanel),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged)); new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
public static readonly DependencyProperty ParentMapProperty = ParentMapPropertyKey.DependencyProperty;
public static MapBase GetParentMap(UIElement element) public static MapBase GetParentMap(UIElement element)
{ {
return (MapBase)element.GetValue(ParentMapProperty); return (MapBase)element.GetValue(ParentMapProperty);
} }
internal void SetParentMap()
{
SetValue(ParentMapPropertyKey, this);
}
} }
} }

View file

@ -18,7 +18,7 @@ namespace MapControl
{ {
internal interface IMapElement internal interface IMapElement
{ {
void ParentMapChanged(MapBase oldParentMap, MapBase newParentMap); MapBase ParentMap { get; set; }
} }
/// <summary> /// <summary>
@ -49,6 +49,41 @@ namespace MapControl
return (Point?)element.GetValue(ViewportPositionProperty); return (Point?)element.GetValue(ViewportPositionProperty);
} }
private MapBase parentMap;
public MapBase ParentMap
{
get { return parentMap; }
set
{
if (parentMap != null && parentMap != this)
{
parentMap.ViewportChanged -= (o, e) => OnViewportChanged();
}
parentMap = value;
if (parentMap != null && parentMap != this)
{
parentMap.ViewportChanged += (o, e) => OnViewportChanged();
OnViewportChanged();
}
}
}
protected virtual void OnViewportChanged()
{
foreach (UIElement element in InternalChildren)
{
var location = GetLocation(element);
if (location != null)
{
SetViewportPosition(element, parentMap, location);
}
}
}
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
foreach (UIElement element in InternalChildren) foreach (UIElement element in InternalChildren)
@ -61,8 +96,6 @@ namespace MapControl
protected override Size ArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize)
{ {
var parentMap = GetParentMap(this);
foreach (UIElement element in InternalChildren) foreach (UIElement element in InternalChildren)
{ {
var rect = new Rect(0d, 0d, element.DesiredSize.Width, element.DesiredSize.Height); var rect = new Rect(0d, 0d, element.DesiredSize.Width, element.DesiredSize.Height);
@ -92,47 +125,13 @@ namespace MapControl
return finalSize; return finalSize;
} }
protected virtual void OnViewportChanged()
{
var parentMap = GetParentMap(this);
foreach (UIElement element in InternalChildren)
{
var location = GetLocation(element);
if (location != null)
{
SetViewportPosition(element, parentMap, location);
}
}
}
private void OnViewportChanged(object sender, EventArgs e)
{
OnViewportChanged();
}
void IMapElement.ParentMapChanged(MapBase oldParentMap, MapBase newParentMap)
{
if (oldParentMap != null && oldParentMap != this)
{
oldParentMap.ViewportChanged -= OnViewportChanged;
}
if (newParentMap != null && newParentMap != this)
{
newParentMap.ViewportChanged += OnViewportChanged;
OnViewportChanged();
}
}
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{ {
var element = obj as IMapElement; var mapElement = obj as IMapElement;
if (element != null) if (mapElement != null)
{ {
element.ParentMapChanged(e.OldValue as MapBase, e.NewValue as MapBase); mapElement.ParentMap = e.NewValue as MapBase;
} }
} }
@ -142,7 +141,10 @@ namespace MapControl
if (element != null) if (element != null)
{ {
SetViewportPosition(element, GetParentMap(element), (Location)e.NewValue); var mapElement = element as IMapElement;
var parentMap = mapElement != null ? mapElement.ParentMap : GetParentMap(element);
SetViewportPosition(element, parentMap, (Location)e.NewValue);
} }
} }

View file

@ -5,38 +5,31 @@
using System.Linq; using System.Linq;
#if NETFX_CORE #if NETFX_CORE
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
#else #else
using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Shapes;
#endif #endif
namespace MapControl namespace MapControl
{ {
public partial class MapPolyline : Path public partial class MapPolyline
{ {
protected readonly PathGeometry Geometry = new PathGeometry();
public MapPolyline() public MapPolyline()
: base(new PathGeometry())
{ {
Data = Geometry;
MapPanel.AddParentMapHandlers(this);
} }
private void UpdateGeometry() protected override void UpdateGeometry()
{ {
var parentMap = MapPanel.GetParentMap(this); var geometry = (PathGeometry)Geometry;
var locations = Locations; var locations = Locations;
Location first; Location first;
Geometry.Figures.Clear(); if (ParentMap != null && locations != null && (first = locations.FirstOrDefault()) != null)
if (parentMap != null && locations != null && (first = locations.FirstOrDefault()) != null)
{ {
var figure = new PathFigure var figure = new PathFigure
{ {
StartPoint = parentMap.MapTransform.Transform(first), StartPoint = ParentMap.MapTransform.Transform(first),
IsClosed = IsClosed, IsClosed = IsClosed,
IsFilled = IsClosed IsFilled = IsClosed
}; };
@ -45,7 +38,7 @@ namespace MapControl
foreach (var location in locations.Skip(1)) foreach (var location in locations.Skip(1))
{ {
segment.Points.Add(parentMap.MapTransform.Transform(location)); segment.Points.Add(ParentMap.MapTransform.Transform(location));
} }
if (segment.Points.Count > 0) if (segment.Points.Count > 0)
@ -53,12 +46,14 @@ namespace MapControl
figure.Segments.Add(segment); figure.Segments.Add(segment);
} }
Geometry.Figures.Add(figure); geometry.Figures.Clear();
Geometry.Transform = parentMap.ViewportTransform; geometry.Figures.Add(figure);
geometry.Transform = ParentMap.ViewportTransform;
} }
else else
{ {
Geometry.Transform = null; geometry.Figures.Clear();
geometry.ClearValue(Geometry.TransformProperty);
} }
} }
} }

View file

@ -4,42 +4,39 @@
using System.Linq; using System.Linq;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Shapes;
namespace MapControl namespace MapControl
{ {
public partial class MapPolyline : Shape public partial class MapPolyline
{ {
protected readonly StreamGeometry Geometry = new StreamGeometry(); public MapPolyline()
: base(new StreamGeometry())
protected override Geometry DefiningGeometry
{ {
get { return Geometry; }
} }
private void UpdateGeometry() protected override void UpdateGeometry()
{ {
var parentMap = MapPanel.GetParentMap(this); var geometry = (StreamGeometry)Geometry;
var locations = Locations; var locations = Locations;
Location first; Location first;
if (parentMap != null && locations != null && (first = locations.FirstOrDefault()) != null) if (ParentMap != null && locations != null && (first = locations.FirstOrDefault()) != null)
{ {
using (var context = Geometry.Open()) using (var context = geometry.Open())
{ {
var startPoint = parentMap.MapTransform.Transform(first); var startPoint = ParentMap.MapTransform.Transform(first);
var points = locations.Skip(1).Select(l => parentMap.MapTransform.Transform(l)).ToList(); var points = locations.Skip(1).Select(l => ParentMap.MapTransform.Transform(l)).ToList();
context.BeginFigure(startPoint, IsClosed, IsClosed); context.BeginFigure(startPoint, IsClosed, IsClosed);
context.PolyLineTo(points, true, false); context.PolyLineTo(points, true, false);
} }
Geometry.Transform = parentMap.ViewportTransform; geometry.Transform = ParentMap.ViewportTransform;
} }
else else
{ {
Geometry.Clear(); geometry.Clear();
Geometry.Transform = null; geometry.ClearValue(Geometry.TransformProperty);
} }
} }
} }

View file

@ -14,7 +14,7 @@ using System.Windows;
namespace MapControl namespace MapControl
{ {
public partial class MapPolyline : IMapElement public partial class MapPolyline : MapShape
{ {
#if NETFX_CORE #if NETFX_CORE
// For WinRT, the Locations dependency property type is declared as object // For WinRT, the Locations dependency property type is declared as object
@ -49,21 +49,6 @@ namespace MapControl
set { SetValue(IsClosedProperty, value); } set { SetValue(IsClosedProperty, value); }
} }
protected override Size MeasureOverride(Size constraint)
{
// Shape.MeasureOverride in WPF and WinRT sometimes return a Size with zero
// width or height, whereas Shape.MeasureOverride in Silverlight occasionally
// throws an ArgumentException, as it tries to create a Size from a negative
// width or height, apparently resulting from a transformed geometry in Path.Data.
// In either case it seems to be sufficient to simply return a non-zero size.
return new Size(1, 1);
}
void IMapElement.ParentMapChanged(MapBase oldParentMap, MapBase newParentMap)
{
UpdateGeometry();
}
private void LocationCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void LocationCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
UpdateGeometry(); UpdateGeometry();

100
MapControl/MapRectangle.cs Normal file
View file

@ -0,0 +1,100 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl
{
public partial class MapRectangle : MapShape
{
private static Transform DefaultFillRelativeTransform =
Brush.RelativeTransformProperty.GetMetadata(typeof(Brush)).DefaultValue as Transform;
public static readonly DependencyProperty SouthProperty = DependencyProperty.Register(
"South", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateGeometry()));
public static readonly DependencyProperty NorthProperty = DependencyProperty.Register(
"North", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateGeometry()));
public static readonly DependencyProperty WestProperty = DependencyProperty.Register(
"West", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateGeometry()));
public static readonly DependencyProperty EastProperty = DependencyProperty.Register(
"East", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateGeometry()));
public MapRectangle()
: base(new RectangleGeometry())
{
}
public double South
{
get { return (double)GetValue(SouthProperty); }
set { SetValue(SouthProperty, value); }
}
public double North
{
get { return (double)GetValue(NorthProperty); }
set { SetValue(NorthProperty, value); }
}
public double West
{
get { return (double)GetValue(WestProperty); }
set { SetValue(WestProperty, value); }
}
public double East
{
get { return (double)GetValue(EastProperty); }
set { SetValue(EastProperty, value); }
}
protected override void UpdateGeometry()
{
var geometry = (RectangleGeometry)Geometry;
if (ParentMap != null &&
!double.IsNaN(South) && !double.IsNaN(North) &&
!double.IsNaN(West) && !double.IsNaN(East) &&
South < North && West < East)
{
var p1 = ParentMap.MapTransform.Transform(new Location(South, West));
var p2 = ParentMap.MapTransform.Transform(new Location(North, East));
geometry.Rect = new Rect(p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.Y);
RenderTransform = ParentMap.ViewportTransform;
}
else
{
geometry.Rect = Rect.Empty;
ClearValue(RenderTransformProperty);
}
}
//#if !NETFX_CORE && !SILVERLIGHT
// protected override void OnRender(DrawingContext drawingContext)
// {
// if (ParentMap != null)
// {
// drawingContext.PushTransform(ParentMap.ViewportTransform);
// drawingContext.DrawRectangle(Fill, null, ((RectangleGeometry)Geometry).Rect);
// drawingContext.Pop();
// }
// }
//#endif
}
}

View file

@ -15,13 +15,16 @@ namespace MapControl
public class MapScale : MapOverlay public class MapScale : MapOverlay
{ {
public static readonly DependencyProperty PaddingProperty = Control.PaddingProperty.AddOwner( public static readonly DependencyProperty PaddingProperty = Control.PaddingProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata(new Thickness(2d))); typeof(MapScale), new FrameworkPropertyMetadata(new Thickness(2d)));
private double length; private double length;
private Size size; private Size size;
static MapScale() static MapScale()
{ {
UIElement.IsHitTestVisibleProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(false));
FrameworkElement.MinWidthProperty.OverrideMetadata( FrameworkElement.MinWidthProperty.OverrideMetadata(
typeof(MapScale), new FrameworkPropertyMetadata(100d)); typeof(MapScale), new FrameworkPropertyMetadata(100d));
@ -46,11 +49,9 @@ namespace MapControl
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var parentMap = MapPanel.GetParentMap(this); if (ParentMap != null && ParentMap.CenterScale > 0d)
if (parentMap != null && parentMap.CenterScale > 0d)
{ {
length = MinWidth / parentMap.CenterScale; length = MinWidth / ParentMap.CenterScale;
var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length))); var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
if (length / magnitude < 2d) if (length / magnitude < 2d)
@ -66,7 +67,7 @@ namespace MapControl
length = 10d * magnitude; length = 10d * magnitude;
} }
size.Width = length * parentMap.CenterScale + StrokeThickness + Padding.Left + Padding.Right; size.Width = length * ParentMap.CenterScale + StrokeThickness + Padding.Left + Padding.Right;
size.Height = FontSize + 2d * StrokeThickness + Padding.Top + Padding.Bottom; size.Height = FontSize + 2d * StrokeThickness + Padding.Top + Padding.Bottom;
} }
else else
@ -79,9 +80,7 @@ namespace MapControl
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
{ {
var parentMap = MapPanel.GetParentMap(this); if (ParentMap != null)
if (parentMap != null)
{ {
var x1 = Padding.Left + StrokeThickness / 2d; var x1 = Padding.Left + StrokeThickness / 2d;
var x2 = size.Width - Padding.Right - StrokeThickness / 2d; var x2 = size.Width - Padding.Right - StrokeThickness / 2d;
@ -89,7 +88,7 @@ namespace MapControl
var y2 = size.Height - Padding.Bottom - StrokeThickness / 2d; var y2 = size.Height - Padding.Bottom - StrokeThickness / 2d;
var text = length >= 1000d ? string.Format("{0:0} km", length / 1000d) : string.Format("{0:0} m", length); var text = length >= 1000d ? string.Format("{0:0} km", length / 1000d) : string.Format("{0:0} m", length);
drawingContext.DrawRectangle(Background ?? parentMap.Background, null, new Rect(size)); drawingContext.DrawRectangle(Background ?? ParentMap.Background, null, new Rect(size));
drawingContext.DrawLine(Pen, new Point(x1, y1), new Point(x1, y2)); drawingContext.DrawLine(Pen, new Point(x1, y1), new Point(x1, y2));
drawingContext.DrawLine(Pen, new Point(x2, y1), new Point(x2, y2)); drawingContext.DrawLine(Pen, new Point(x2, y1), new Point(x2, y2));
drawingContext.DrawLine(Pen, new Point(x1, y2), new Point(x2, y2)); drawingContext.DrawLine(Pen, new Point(x1, y2), new Point(x2, y2));

View file

@ -0,0 +1,23 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
#else
using System.Windows.Media;
using System.Windows.Shapes;
#endif
namespace MapControl
{
public partial class MapShape : Path
{
public MapShape(Geometry geometry)
{
Data = Geometry = geometry;
MapPanel.AddParentMapHandlers(this);
}
}
}

View file

@ -0,0 +1,22 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System.Windows.Media;
using System.Windows.Shapes;
namespace MapControl
{
public partial class MapShape : Shape
{
public MapShape(Geometry geometry)
{
Geometry = geometry;
}
protected override Geometry DefiningGeometry
{
get { return Geometry; }
}
}
}

49
MapControl/MapShape.cs Normal file
View file

@ -0,0 +1,49 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2013 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl
{
/// <summary>
/// Base class for map shapes.
/// </summary>
public partial class MapShape : IMapElement
{
private MapBase parentMap;
public MapBase ParentMap
{
get { return parentMap; }
set
{
parentMap = value;
UpdateGeometry();
}
}
protected readonly Geometry Geometry;
protected virtual void UpdateGeometry()
{
}
protected override Size MeasureOverride(Size constraint)
{
// Shape.MeasureOverride in WPF and WinRT sometimes return a Size with zero
// width or height, whereas Shape.MeasureOverride in Silverlight occasionally
// throws an ArgumentException, as it tries to create a Size from a negative
// width or height, apparently resulting from a transformed Geometry.
// In either case it seems to be sufficient to simply return a non-zero size.
return new Size(1, 1);
}
}
}

View file

@ -16,6 +16,6 @@ using System.Windows;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -63,6 +63,9 @@
<Compile Include="..\MapGraticule.Silverlight.WinRT.cs"> <Compile Include="..\MapGraticule.Silverlight.WinRT.cs">
<Link>MapGraticule.Silverlight.WinRT.cs</Link> <Link>MapGraticule.Silverlight.WinRT.cs</Link>
</Compile> </Compile>
<Compile Include="..\MapImage.cs">
<Link>MapImage.cs</Link>
</Compile>
<Compile Include="..\MapItem.Silverlight.WinRT.cs"> <Compile Include="..\MapItem.Silverlight.WinRT.cs">
<Link>MapItem.Silverlight.WinRT.cs</Link> <Link>MapItem.Silverlight.WinRT.cs</Link>
</Compile> </Compile>
@ -72,12 +75,6 @@
<Compile Include="..\MapItemsControl.Silverlight.WinRT.cs"> <Compile Include="..\MapItemsControl.Silverlight.WinRT.cs">
<Link>MapItemsControl.Silverlight.WinRT.cs</Link> <Link>MapItemsControl.Silverlight.WinRT.cs</Link>
</Compile> </Compile>
<Compile Include="..\MapOverlay.cs">
<Link>MapOverlay.cs</Link>
</Compile>
<Compile Include="..\MapOverlay.Silverlight.WinRT.cs">
<Link>MapOverlay.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\MapPanel.cs"> <Compile Include="..\MapPanel.cs">
<Link>MapPanel.cs</Link> <Link>MapPanel.cs</Link>
</Compile> </Compile>
@ -90,6 +87,15 @@
<Compile Include="..\MapPolyline.Silverlight.WinRT.cs"> <Compile Include="..\MapPolyline.Silverlight.WinRT.cs">
<Link>MapPolyline.Silverlight.WinRT.cs</Link> <Link>MapPolyline.Silverlight.WinRT.cs</Link>
</Compile> </Compile>
<Compile Include="..\MapRectangle.cs">
<Link>MapRectangle.cs</Link>
</Compile>
<Compile Include="..\MapShape.cs">
<Link>MapShape.cs</Link>
</Compile>
<Compile Include="..\MapShape.Silverlight.WinRT.cs">
<Link>MapShape.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\MapTransform.cs"> <Compile Include="..\MapTransform.cs">
<Link>MapTransform.cs</Link> <Link>MapTransform.cs</Link>
</Compile> </Compile>

View file

@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

View file

@ -105,6 +105,8 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<map:Map x:Name="map" Center="53.5,8.2" MinZoomLevel="2" MaxZoomLevel="18" ZoomLevel="11" <map:Map x:Name="map" Center="53.5,8.2" MinZoomLevel="2" MaxZoomLevel="18" ZoomLevel="11"
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave"> MouseMove="MapMouseMove" MouseLeave="MapMouseLeave">
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"
Source="10_535_330.jpg" Opacity=".5"/>
<map:MapGraticule Opacity="0.6"/> <map:MapGraticule Opacity="0.6"/>
<!-- use ItemTemplate or ItemContainerStyle alternatively --> <!-- use ItemTemplate or ItemContainerStyle alternatively -->
@ -136,16 +138,27 @@
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Name="mouseLocation" Margin="4" VerticalAlignment="Center"/> <TextBlock Name="mouseLocation" Margin="4" VerticalAlignment="Bottom" FontFamily="Consolas"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Slider Margin="4" Width="100" SmallChange="0.01" <StackPanel Margin="5">
Maximum="{Binding MaxZoomLevel, ElementName=map}" <TextBlock Text="Zoom Level" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
Minimum="{Binding MinZoomLevel, ElementName=map}" <Slider Width="100" SmallChange="0.01"
Value="{Binding TargetZoomLevel, ElementName=map, Mode=TwoWay}"/> Maximum="{Binding MaxZoomLevel, ElementName=map}"
<Slider Margin="4" Width="100" Minimum="0" Maximum="360" SmallChange="5" LargeChange="45" Minimum="{Binding MinZoomLevel, ElementName=map}"
Value="{Binding TargetHeading, ElementName=map, Mode=TwoWay}"/> Value="{Binding TargetZoomLevel, ElementName=map, Mode=TwoWay}"/>
<CheckBox Margin="4" VerticalAlignment="Center" Content="Seamarks" Click="SeamarksClick"/> </StackPanel>
<ComboBox Margin="4" Width="120" SelectedIndex="0" SelectionChanged="TileLayerSelectionChanged"> <StackPanel Margin="5">
<TextBlock Text="Heading" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
<Slider Width="100" SmallChange="5" LargeChange="45" Minimum="0" Maximum="360"
Value="{Binding TargetHeading, ElementName=map, Mode=TwoWay}"/>
</StackPanel>
<StackPanel Margin="5">
<TextBlock Text="Image Opacity" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
<Slider Width="100" Minimum="0" Maximum="1"
Value="{Binding Opacity, ElementName=mapImage, Mode=TwoWay}"/>
</StackPanel>
<CheckBox Margin="5" VerticalAlignment="Bottom" Content="Seamarks" Click="SeamarksClick"/>
<ComboBox Margin="5" VerticalAlignment="Bottom" Width="120" SelectedIndex="0" SelectionChanged="TileLayerSelectionChanged">
<sys:String>OpenStreetMap</sys:String> <sys:String>OpenStreetMap</sys:String>
<sys:String>OpenCycleMap</sys:String> <sys:String>OpenCycleMap</sys:String>
<sys:String>OCM Transport</sys:String> <sys:String>OCM Transport</sys:String>

View file

@ -1,6 +1,7 @@
using MapControl; using MapControl;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
@ -20,7 +21,7 @@ namespace SilverlightApplication
{ {
InitializeComponent(); InitializeComponent();
ICollection<object> polylines = (ICollection<object>)Resources["Polylines"]; var polylines = (ICollection<object>)Resources["Polylines"];
polylines.Add( polylines.Add(
new SamplePolyline new SamplePolyline
{ {
@ -32,7 +33,7 @@ namespace SilverlightApplication
Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212") Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212")
}); });
ICollection<object> points = (ICollection<object>)Resources["Points"]; var points = (ICollection<object>)Resources["Points"];
points.Add( points.Add(
new SamplePoint new SamplePoint
{ {
@ -71,7 +72,7 @@ namespace SilverlightApplication
}); });
points.Add(movingPoint); points.Add(movingPoint);
ICollection<object> pushpins = (ICollection<object>)Resources["Pushpins"]; var pushpins = (ICollection<object>)Resources["Pushpins"];
pushpins.Add( pushpins.Add(
new SamplePoint new SamplePoint
{ {
@ -97,8 +98,7 @@ namespace SilverlightApplication
Location = new Location(53.5207, 8.2323) Location = new Location(53.5207, 8.2323)
}); });
DispatcherTimer timer = new DispatcherTimer(); var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) };
timer.Interval = TimeSpan.FromSeconds(0.1);
timer.Tick += MovePoint; timer.Tick += MovePoint;
timer.Start(); timer.Start();
} }
@ -121,7 +121,15 @@ namespace SilverlightApplication
private void MapMouseMove(object sender, MouseEventArgs e) private void MapMouseMove(object sender, MouseEventArgs e)
{ {
mouseLocation.Text = map.ViewportPointToLocation(e.GetPosition(map)).ToString(); var location = map.ViewportPointToLocation(e.GetPosition(map));
var longitude = Location.NormalizeLongitude(location.Longitude);
var latString = location.Latitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "S {0:00.00000}", -location.Latitude) :
string.Format(CultureInfo.InvariantCulture, "N {0:00.00000}", location.Latitude);
var lonString = longitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "W {0:000.00000}", -longitude) :
string.Format(CultureInfo.InvariantCulture, "E {0:000.00000}", longitude);
mouseLocation.Text = latString + "\n" + lonString;
} }
private void TileLayerSelectionChanged(object sender, SelectionChangedEventArgs e) private void TileLayerSelectionChanged(object sender, SelectionChangedEventArgs e)

View file

@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -107,6 +107,9 @@
<Name>MapControl.Silverlight</Name> <Name>MapControl.Silverlight</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="10_535_330.jpg" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

View file

@ -107,6 +107,8 @@
<map:MapBase.Center> <map:MapBase.Center>
<map:Location Latitude="53.5" Longitude="8.2"/> <map:Location Latitude="53.5" Longitude="8.2"/>
</map:MapBase.Center> </map:MapBase.Center>
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"
Source="10_535_330.jpg" Opacity=".5"/>
<map:MapGraticule Foreground="Black" Opacity="0.6"/> <map:MapGraticule Foreground="Black" Opacity="0.6"/>
<!-- use ItemTemplate or ItemContainerStyle alternatively --> <!-- use ItemTemplate or ItemContainerStyle alternatively -->
@ -145,16 +147,25 @@
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Name="mouseLocation" Margin="4" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Slider Margin="10,0,10,0" Width="200" SmallChange="0.1" <StackPanel Margin="5">
Minimum="{Binding MinZoomLevel, ElementName=map}" <TextBlock Text="Zoom Level" HorizontalAlignment="Center" Foreground="Gray" FontSize="14"/>
Maximum="{Binding MaxZoomLevel, ElementName=map}" <Slider Margin="10,-10,10,-10" Width="200" SmallChange="0.1"
Value="{Binding TargetZoomLevel, ElementName=map, Mode=TwoWay}"/> Minimum="{Binding MinZoomLevel, ElementName=map}"
<Slider Margin="10,0,10,0" Width="200" Minimum="0" Maximum="360" SmallChange="5" LargeChange="45" Maximum="{Binding MaxZoomLevel, ElementName=map}"
Value="{Binding Heading, ElementName=map, Mode=TwoWay}"/> Value="{Binding TargetZoomLevel, ElementName=map, Mode=TwoWay}"/>
</StackPanel>
<StackPanel Margin="5">
<TextBlock Text="Heading" HorizontalAlignment="Center" Foreground="Gray" FontSize="14"/>
<Slider Margin="10,-10,10,-10" Width="200" Minimum="0" Maximum="360" SmallChange="5" LargeChange="45"
Value="{Binding Heading, ElementName=map, Mode=TwoWay}"/>
</StackPanel>
<StackPanel Margin="5">
<TextBlock Text="Image Opacity" HorizontalAlignment="Center" Foreground="Gray" FontSize="14"/>
<Slider Margin="10,-10,10,-10" Width="200" Value="50" ValueChanged="ImageOpacitySliderValueChanged"/>
</StackPanel>
<CheckBox Margin="10" VerticalAlignment="Center" Content="Seamarks" Click="SeamarksClick"/> <CheckBox Margin="10" VerticalAlignment="Center" Content="Seamarks" Click="SeamarksClick"/>
<ComboBox Margin="10" Width="200" SelectedIndex="0" SelectionChanged="TileLayerSelectionChanged"> <ComboBox Margin="10" Width="200" VerticalAlignment="Center" SelectedIndex="0" SelectionChanged="TileLayerSelectionChanged">
<ComboBoxItem>OpenStreetMap</ComboBoxItem> <ComboBoxItem>OpenStreetMap</ComboBoxItem>
<ComboBoxItem>OpenCycleMap</ComboBoxItem> <ComboBoxItem>OpenCycleMap</ComboBoxItem>
<ComboBoxItem>OCM Transport</ComboBoxItem> <ComboBoxItem>OCM Transport</ComboBoxItem>

View file

@ -3,7 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Controls.Primitives;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
@ -24,7 +24,7 @@ namespace StoreApplication
{ {
this.InitializeComponent(); this.InitializeComponent();
ICollection<object> polylines = (ICollection<object>)Resources["Polylines"]; var polylines = (ICollection<object>)Resources["Polylines"];
polylines.Add( polylines.Add(
new SamplePolyline new SamplePolyline
{ {
@ -36,7 +36,7 @@ namespace StoreApplication
Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212") Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212")
}); });
ICollection<object> points = (ICollection<object>)Resources["Points"]; var points = (ICollection<object>)Resources["Points"];
points.Add( points.Add(
new SamplePoint new SamplePoint
{ {
@ -75,7 +75,7 @@ namespace StoreApplication
}); });
points.Add(movingPoint); points.Add(movingPoint);
ICollection<object> pushpins = (ICollection<object>)Resources["Pushpins"]; var pushpins = (ICollection<object>)Resources["Pushpins"];
pushpins.Add( pushpins.Add(
new SamplePoint new SamplePoint
{ {
@ -101,8 +101,7 @@ namespace StoreApplication
Location = new Location(53.5207, 8.2323) Location = new Location(53.5207, 8.2323)
}); });
DispatcherTimer timer = new DispatcherTimer(); var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) };
timer.Interval = TimeSpan.FromSeconds(0.1);
timer.Tick += MovePoint; timer.Tick += MovePoint;
timer.Start(); timer.Start();
} }
@ -118,13 +117,12 @@ namespace StoreApplication
} }
} }
/// <summary> private void ImageOpacitySliderValueChanged(object sender, RangeBaseValueChangedEventArgs e)
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{ {
if (mapImage != null)
{
mapImage.Opacity = e.NewValue / 100;
}
} }
private void SeamarksClick(object sender, RoutedEventArgs e) private void SeamarksClick(object sender, RoutedEventArgs e)

View file

@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -50,6 +50,7 @@
</AppxManifest> </AppxManifest>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="10_535_330.jpg" />
<Content Include="Assets\Logo.png" /> <Content Include="Assets\Logo.png" />
<Content Include="Assets\SmallLogo.png" /> <Content Include="Assets\SmallLogo.png" />
<Content Include="Assets\SplashScreen.png" /> <Content Include="Assets\SplashScreen.png" />

View file

@ -10,7 +10,7 @@ using System.Windows;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

View file

@ -155,6 +155,8 @@
MouseLeftButtonDown="MapMouseLeftButtonDown" MouseRightButtonDown="MapMouseRightButtonDown" MouseLeftButtonDown="MapMouseLeftButtonDown" MouseRightButtonDown="MapMouseRightButtonDown"
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave" MouseMove="MapMouseMove" MouseLeave="MapMouseLeave"
ManipulationInertiaStarting="MapManipulationInertiaStarting"> ManipulationInertiaStarting="MapManipulationInertiaStarting">
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"
Source="10_535_330.jpg" Opacity=".5"/>
<map:MapGraticule Opacity="0.6"/> <map:MapGraticule Opacity="0.6"/>
<map:MapScale Margin="4" Opacity="0.8"/> <map:MapScale Margin="4" Opacity="0.8"/>
@ -196,17 +198,28 @@
<ColumnDefinition/> <ColumnDefinition/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Name="mouseLocation" Margin="4" VerticalAlignment="Center"/> <TextBlock Name="mouseLocation" Margin="5" VerticalAlignment="Bottom" FontFamily="Consolas"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Slider ToolTip="Zoom Level" Margin="4" Width="100" SmallChange="0.01" <StackPanel Margin="5">
Minimum="{Binding MinZoomLevel, ElementName=map}" <TextBlock Text="Zoom Level" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
Maximum="{Binding MaxZoomLevel, ElementName=map}" <Slider ToolTip="Zoom Level" Width="100" VerticalAlignment="Center" SmallChange="0.01"
Value="{Binding TargetZoomLevel, ElementName=map}"/> Minimum="{Binding MinZoomLevel, ElementName=map}"
<Slider ToolTip="Heading" Margin="4" Width="100" Minimum="0" Maximum="360" SmallChange="5" LargeChange="45" Maximum="{Binding MaxZoomLevel, ElementName=map}"
Value="{Binding TargetHeading, ElementName=map}"/> Value="{Binding TargetZoomLevel, ElementName=map}"/>
<CheckBox ToolTip="Map Overlay" Margin="4" VerticalAlignment="Center" Content="Seamarks" Click="SeamarksClick"/> </StackPanel>
<ComboBox ToolTip="Main Tile Layer" Margin="4" DisplayMemberPath="SourceName" SelectedIndex="0" <StackPanel Margin="5">
ItemsSource="{Binding Source={StaticResource TileLayersView}}"/> <TextBlock Text="Heading" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
<Slider ToolTip="Heading" Width="100" VerticalAlignment="Center" SmallChange="5" LargeChange="45"
Minimum="0" Maximum="360" Value="{Binding TargetHeading, ElementName=map}"/>
</StackPanel>
<StackPanel Margin="5">
<TextBlock Text="Image Opacity" Margin="0,0,0,2" HorizontalAlignment="Center" Foreground="Gray" FontSize="10"/>
<Slider ToolTip="Image Opacity" Width="100" VerticalAlignment="Center"
Minimum="0" Maximum="1" Value="{Binding Opacity, ElementName=mapImage}"/>
</StackPanel>
<CheckBox ToolTip="Seamarks Overlay" Margin="7" VerticalAlignment="Bottom" Content="Seamarks" Click="SeamarksClick"/>
<ComboBox ToolTip="Tile Layer" Margin="5" VerticalAlignment="Bottom" DisplayMemberPath="SourceName"
SelectedIndex="0" ItemsSource="{Binding Source={StaticResource TileLayersView}}"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Grid> </Grid>

View file

@ -2,6 +2,7 @@
using MapControl; using MapControl;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
@ -33,7 +34,7 @@ namespace WpfApplication
InitializeComponent(); InitializeComponent();
ICollection<object> polylines = (ICollection<object>)Resources["Polylines"]; var polylines = (ICollection<object>)Resources["Polylines"];
polylines.Add( polylines.Add(
new SamplePolyline new SamplePolyline
{ {
@ -45,7 +46,7 @@ namespace WpfApplication
Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212") Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212")
}); });
ICollection<object> points = (ICollection<object>)Resources["Points"]; var points = (ICollection<object>)Resources["Points"];
points.Add( points.Add(
new SamplePoint new SamplePoint
{ {
@ -84,7 +85,7 @@ namespace WpfApplication
}); });
points.Add(movingPoint); points.Add(movingPoint);
ICollection<object> pushpins = (ICollection<object>)Resources["Pushpins"]; var pushpins = (ICollection<object>)Resources["Pushpins"];
pushpins.Add( pushpins.Add(
new SamplePoint new SamplePoint
{ {
@ -110,8 +111,7 @@ namespace WpfApplication
Location = new Location(53.5207, 8.2323) Location = new Location(53.5207, 8.2323)
}); });
DispatcherTimer timer = new DispatcherTimer(); var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) };
timer.Interval = TimeSpan.FromSeconds(0.1);
timer.Tick += MovePoint; timer.Tick += MovePoint;
timer.Start(); timer.Start();
} }
@ -151,7 +151,15 @@ namespace WpfApplication
private void MapMouseMove(object sender, MouseEventArgs e) private void MapMouseMove(object sender, MouseEventArgs e)
{ {
mouseLocation.Text = map.ViewportPointToLocation(e.GetPosition(map)).ToString(); var location = map.ViewportPointToLocation(e.GetPosition(map));
var longitude = Location.NormalizeLongitude(location.Longitude);
var latString = location.Latitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "S {0:00.00000}", -location.Latitude) :
string.Format(CultureInfo.InvariantCulture, "N {0:00.00000}", location.Latitude);
var lonString = longitude < 0 ?
string.Format(CultureInfo.InvariantCulture, "W {0:000.00000}", -longitude) :
string.Format(CultureInfo.InvariantCulture, "E {0:000.00000}", longitude);
mouseLocation.Text = latString + "\n" + lonString;
} }
private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e) private void MapManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)

View file

@ -10,7 +10,7 @@ using System.Windows;
[assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")] [assembly: AssemblyCopyright("Copyright © 2013 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.1.10")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.10")] [assembly: AssemblyFileVersion("1.2.0")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]

View file

@ -96,6 +96,9 @@
<Name>MapControl.WPF</Name> <Name>MapControl.WPF</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="10_535_330.jpg" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.