mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-04 14:08:32 +00:00
Version 4: Upgrade to VS 2017
This commit is contained in:
parent
2aafe32e00
commit
ec47f225b3
142 changed files with 1828 additions and 18384 deletions
54
MapControl/UWP/Extensions.UWP.cs
Normal file
54
MapControl/UWP/Extensions.UWP.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
internal static class Extensions
|
||||
{
|
||||
public static Point Transform(this GeneralTransform transform, Point point)
|
||||
{
|
||||
return transform.TransformPoint(point);
|
||||
}
|
||||
|
||||
public static void BeginAnimation(this DependencyObject obj, DependencyProperty property, DoubleAnimation animation)
|
||||
{
|
||||
animation.EnableDependentAnimation = true;
|
||||
BeginAnimation(obj, property, (Timeline)animation);
|
||||
}
|
||||
|
||||
public static void BeginAnimation(this DependencyObject obj, DependencyProperty property, PointAnimation animation)
|
||||
{
|
||||
animation.EnableDependentAnimation = true;
|
||||
BeginAnimation(obj, property, (Timeline)animation);
|
||||
}
|
||||
|
||||
private static Dictionary<DependencyProperty, string> properties = new Dictionary<DependencyProperty, string>()
|
||||
{
|
||||
{ UIElement.OpacityProperty, "Opacity" },
|
||||
{ MapBase.ZoomLevelProperty, "ZoomLevel" },
|
||||
{ MapBase.HeadingProperty, "Heading" },
|
||||
{ MapBase.CenterPointProperty, "CenterPoint" }
|
||||
};
|
||||
|
||||
private static void BeginAnimation(DependencyObject obj, DependencyProperty property, Timeline animation)
|
||||
{
|
||||
string propertyName;
|
||||
|
||||
if (properties.TryGetValue(property, out propertyName))
|
||||
{
|
||||
Storyboard.SetTargetProperty(animation, propertyName);
|
||||
Storyboard.SetTarget(animation, obj);
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(animation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
MapControl/UWP/ImageCache.UWP.cs
Normal file
22
MapControl/UWP/ImageCache.UWP.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace MapControl.Caching
|
||||
{
|
||||
public class ImageCacheItem
|
||||
{
|
||||
public IBuffer Buffer { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
}
|
||||
|
||||
public interface IImageCache
|
||||
{
|
||||
Task<ImageCacheItem> GetAsync(string key);
|
||||
Task SetAsync(string key, IBuffer buffer, DateTime expiration);
|
||||
}
|
||||
}
|
||||
99
MapControl/UWP/ImageFileCache.UWP.cs
Normal file
99
MapControl/UWP/ImageFileCache.UWP.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace MapControl.Caching
|
||||
{
|
||||
public class ImageFileCache : IImageCache
|
||||
{
|
||||
private StorageFolder rootFolder;
|
||||
|
||||
public ImageFileCache(StorageFolder rootFolder)
|
||||
{
|
||||
if (rootFolder == null)
|
||||
{
|
||||
throw new ArgumentNullException("The parameter rootFolder must not be null.");
|
||||
}
|
||||
|
||||
this.rootFolder = rootFolder;
|
||||
|
||||
Debug.WriteLine("Created ImageFileCache in " + rootFolder.Path);
|
||||
}
|
||||
|
||||
public virtual async Task<ImageCacheItem> GetAsync(string key)
|
||||
{
|
||||
string path = null;
|
||||
|
||||
try
|
||||
{
|
||||
path = Path.Combine(key.Split('\\', '/', ':', ';'));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Invalid key {0}: {1}", key, ex.Message);
|
||||
}
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
var item = await rootFolder.TryGetItemAsync(path);
|
||||
|
||||
if (item != null && item.IsOfType(StorageItemTypes.File))
|
||||
{
|
||||
var file = (StorageFile)item;
|
||||
//Debug.WriteLine("ImageFileCache: Reading " + file.Path);
|
||||
|
||||
try
|
||||
{
|
||||
return new ImageCacheItem
|
||||
{
|
||||
Buffer = await FileIO.ReadBufferAsync(file),
|
||||
Expiration = (await file.Properties.GetImagePropertiesAsync()).DateTaken.UtcDateTime
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Reading {0}: {1}", file.Path, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual async Task SetAsync(string key, IBuffer buffer, DateTime expiration)
|
||||
{
|
||||
var paths = key.Split('\\', '/', ':', ';');
|
||||
|
||||
try
|
||||
{
|
||||
var folder = rootFolder;
|
||||
|
||||
for (int i = 0; i < paths.Length - 1; i++)
|
||||
{
|
||||
folder = await folder.CreateFolderAsync(paths[i], CreationCollisionOption.OpenIfExists);
|
||||
}
|
||||
|
||||
var file = await folder.CreateFileAsync(paths[paths.Length - 1], CreationCollisionOption.ReplaceExisting);
|
||||
//Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", file.Path, expiration.ToLocalTime());
|
||||
|
||||
await FileIO.WriteBufferAsync(file, buffer);
|
||||
|
||||
// Store expiration date in ImageProperties.DateTaken
|
||||
var properties = await file.Properties.GetImagePropertiesAsync();
|
||||
properties.DateTaken = expiration;
|
||||
await properties.SavePropertiesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Writing {0}\\{1}: {2}", rootFolder.Path, string.Join("\\", paths), ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
MapControl/UWP/Map.UWP.cs
Normal file
75
MapControl/UWP/Map.UWP.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Input;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// MapBase with default input event handling.
|
||||
/// </summary>
|
||||
public class Map : MapBase
|
||||
{
|
||||
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
|
||||
nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d));
|
||||
|
||||
private bool transformPending;
|
||||
private Point transformTranslation;
|
||||
private double transformRotation;
|
||||
private double transformScale = 1d;
|
||||
|
||||
public Map()
|
||||
{
|
||||
ManipulationMode = ManipulationModes.Scale |
|
||||
ManipulationModes.TranslateX | ManipulationModes.TranslateY | ManipulationModes.TranslateInertia;
|
||||
|
||||
ManipulationDelta += OnManipulationDelta;
|
||||
PointerWheelChanged += OnPointerWheelChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount by which the ZoomLevel property changes during a MouseWheel event.
|
||||
/// </summary>
|
||||
public double MouseWheelZoomDelta
|
||||
{
|
||||
get { return (double)GetValue(MouseWheelZoomDeltaProperty); }
|
||||
set { SetValue(MouseWheelZoomDeltaProperty, value); }
|
||||
}
|
||||
|
||||
protected virtual void OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
var point = e.GetCurrentPoint(this);
|
||||
var zoomChange = MouseWheelZoomDelta * point.Properties.MouseWheelDelta / 120d;
|
||||
|
||||
ZoomMap(point.Position, TargetZoomLevel + zoomChange);
|
||||
}
|
||||
|
||||
protected virtual async void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
|
||||
{
|
||||
transformTranslation.X += e.Delta.Translation.X;
|
||||
transformTranslation.Y += e.Delta.Translation.Y;
|
||||
transformRotation += e.Delta.Rotation;
|
||||
transformScale *= e.Delta.Scale;
|
||||
|
||||
if (!transformPending)
|
||||
{
|
||||
transformPending = true;
|
||||
|
||||
await Dispatcher.RunIdleAsync(a =>
|
||||
{
|
||||
TransformMap(e.Position, transformTranslation, transformRotation, transformScale);
|
||||
|
||||
transformPending = false;
|
||||
transformTranslation.X = 0d;
|
||||
transformTranslation.Y = 0d;
|
||||
transformRotation = 0d;
|
||||
transformScale = 1d;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
MapControl/UWP/MapBase.UWP.cs
Normal file
64
MapControl/UWP/MapBase.UWP.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapBase
|
||||
{
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||
nameof(Foreground), typeof(Brush), typeof(MapBase),
|
||||
new PropertyMetadata(new SolidColorBrush(Colors.Black)));
|
||||
|
||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
||||
nameof(Center), typeof(Location), typeof(MapBase),
|
||||
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
||||
nameof(TargetCenter), typeof(Location), typeof(MapBase),
|
||||
new PropertyMetadata(new Location(), (o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
||||
nameof(ZoomLevel), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(1d, (o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
|
||||
nameof(TargetZoomLevel), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(1d, (o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
|
||||
nameof(Heading), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(0d, (o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
|
||||
nameof(TargetHeading), typeof(double), typeof(MapBase),
|
||||
new PropertyMetadata(0d, (o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
||||
|
||||
partial void Initialize()
|
||||
{
|
||||
// set Background by Style to enable resetting by ClearValue in MapLayerPropertyChanged
|
||||
var style = new Style(typeof(MapBase));
|
||||
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
|
||||
Style = style;
|
||||
|
||||
var clip = new RectangleGeometry();
|
||||
Clip = clip;
|
||||
|
||||
SizeChanged += (s, e) =>
|
||||
{
|
||||
if (clip.Rect.Width != e.NewSize.Width || clip.Rect.Height != e.NewSize.Height)
|
||||
{
|
||||
clip.Rect = new Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height);
|
||||
|
||||
ResetTransformCenter();
|
||||
UpdateTransform();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
180
MapControl/UWP/MapControl.UWP.csproj
Normal file
180
MapControl/UWP/MapControl.UWP.csproj
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{951BC5D2-D653-42D9-9A91-21DC50DE0182}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MapControl</RootNamespace>
|
||||
<AssemblyName>MapControl.UWP</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<GenerateLibraryLayout>true</GenerateLibraryLayout>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<GenerateLibraryLayout>true</GenerateLibraryLayout>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
|
||||
<None Include="..\..\MapControl.snk">
|
||||
<Link>MapControl.snk</Link>
|
||||
</None>
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\AzimuthalEquidistantProjection.cs">
|
||||
<Link>AzimuthalEquidistantProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\AzimuthalProjection.cs">
|
||||
<Link>AzimuthalProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\BingMapsTileLayer.cs">
|
||||
<Link>BingMapsTileLayer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\BingMapsTileSource.cs">
|
||||
<Link>BingMapsTileSource.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\BoundingBox.cs">
|
||||
<Link>BoundingBox.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\CenteredBoundingBox.cs">
|
||||
<Link>CenteredBoundingBox.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\EquirectangularProjection.cs">
|
||||
<Link>EquirectangularProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\GnomonicProjection.cs">
|
||||
<Link>GnomonicProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\HyperlinkText.cs">
|
||||
<Link>HyperlinkText.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Location.cs">
|
||||
<Link>Location.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\LocationCollection.cs">
|
||||
<Link>LocationCollection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapBase.cs">
|
||||
<Link>MapBase.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapGraticule.cs">
|
||||
<Link>MapGraticule.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapImageLayer.cs">
|
||||
<Link>MapImageLayer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapOverlay.cs">
|
||||
<Link>MapOverlay.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapPanel.cs">
|
||||
<Link>MapPanel.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapPath.cs">
|
||||
<Link>MapPath.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapPolyline.cs">
|
||||
<Link>MapPolyline.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapProjection.cs">
|
||||
<Link>MapProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\MapTileLayer.cs">
|
||||
<Link>MapTileLayer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\OrthographicProjection.cs">
|
||||
<Link>OrthographicProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\StereographicProjection.cs">
|
||||
<Link>StereographicProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Tile.cs">
|
||||
<Link>Tile.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\TileGrid.cs">
|
||||
<Link>TileGrid.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\TileImageLoader.cs">
|
||||
<Link>TileImageLoader.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\TileSource.cs">
|
||||
<Link>TileSource.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\ViewportChangedEventArgs.cs">
|
||||
<Link>ViewportChangedEventArgs.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\WebMercatorProjection.cs">
|
||||
<Link>WebMercatorProjection.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\WmsImageLayer.cs">
|
||||
<Link>WmsImageLayer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Extensions.UWP.cs" />
|
||||
<Compile Include="ImageCache.UWP.cs" />
|
||||
<Compile Include="ImageFileCache.UWP.cs" />
|
||||
<Compile Include="Map.UWP.cs" />
|
||||
<Compile Include="MapBase.UWP.cs" />
|
||||
<Compile Include="MapGraticule.UWP.cs" />
|
||||
<Compile Include="MapImageLayer.UWP.cs" />
|
||||
<Compile Include="MapItem.UWP.cs" />
|
||||
<Compile Include="MapItemsControl.UWP.cs" />
|
||||
<Compile Include="MapOverlay.UWP.cs" />
|
||||
<Compile Include="MapPanel.UWP.cs" />
|
||||
<Compile Include="MapPath.UWP.cs" />
|
||||
<Compile Include="MapPolyline.UWP.cs" />
|
||||
<Compile Include="MapTileLayer.UWP.cs" />
|
||||
<Compile Include="MatrixEx.UWP.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Pushpin.UWP.cs" />
|
||||
<Compile Include="Tile.UWP.cs" />
|
||||
<Compile Include="TileImageLoader.UWP.cs" />
|
||||
<EmbeddedResource Include="Properties\MapControl.UWP.rd.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Themes\Generic.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- 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.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
208
MapControl/UWP/MapGraticule.UWP.cs
Normal file
208
MapControl/UWP/MapGraticule.UWP.cs
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapGraticule
|
||||
{
|
||||
private Path path;
|
||||
private Location graticuleStart;
|
||||
private Location graticuleEnd;
|
||||
|
||||
public MapGraticule()
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
StrokeThickness = 0.5;
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||
{
|
||||
var projection = ParentMap.MapProjection;
|
||||
|
||||
if (!double.IsNaN(projection.LongitudeScale))
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
path = new Path
|
||||
{
|
||||
Data = new PathGeometry()
|
||||
};
|
||||
|
||||
path.SetBinding(Shape.StrokeProperty,
|
||||
GetBindingExpression(StrokeProperty)?.ParentBinding ??
|
||||
new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath("Stroke")
|
||||
});
|
||||
|
||||
path.SetBinding(Shape.StrokeThicknessProperty,
|
||||
GetBindingExpression(StrokeThicknessProperty)?.ParentBinding ??
|
||||
new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath("StrokeThickness")
|
||||
});
|
||||
|
||||
Children.Add(path);
|
||||
}
|
||||
|
||||
var bounds = projection.ViewportRectToBoundingBox(new Rect(0d, 0d, ParentMap.RenderSize.Width, ParentMap.RenderSize.Height));
|
||||
var lineDistance = GetLineDistance();
|
||||
|
||||
var labelStart = new Location(
|
||||
Math.Ceiling(bounds.South / lineDistance) * lineDistance,
|
||||
Math.Ceiling(bounds.West / lineDistance) * lineDistance);
|
||||
|
||||
var labelEnd = new Location(
|
||||
Math.Floor(bounds.North / lineDistance) * lineDistance,
|
||||
Math.Floor(bounds.East / lineDistance) * lineDistance);
|
||||
|
||||
var lineStart = new Location(
|
||||
Math.Min(Math.Max(labelStart.Latitude - lineDistance, -projection.MaxLatitude), projection.MaxLatitude),
|
||||
labelStart.Longitude - lineDistance);
|
||||
|
||||
var lineEnd = new Location(
|
||||
Math.Min(Math.Max(labelEnd.Latitude + lineDistance, -projection.MaxLatitude), projection.MaxLatitude),
|
||||
labelEnd.Longitude + lineDistance);
|
||||
|
||||
if (!lineStart.Equals(graticuleStart) || !lineEnd.Equals(graticuleEnd))
|
||||
{
|
||||
graticuleStart = lineStart;
|
||||
graticuleEnd = lineEnd;
|
||||
|
||||
var geometry = (PathGeometry)path.Data;
|
||||
geometry.Figures.Clear();
|
||||
geometry.Transform = projection.ViewportTransform;
|
||||
|
||||
for (var lat = labelStart.Latitude; lat <= bounds.North; lat += lineDistance)
|
||||
{
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = projection.LocationToPoint(new Location(lat, lineStart.Longitude)),
|
||||
IsClosed = false,
|
||||
IsFilled = false
|
||||
};
|
||||
|
||||
figure.Segments.Add(new LineSegment
|
||||
{
|
||||
Point = projection.LocationToPoint(new Location(lat, lineEnd.Longitude)),
|
||||
});
|
||||
|
||||
geometry.Figures.Add(figure);
|
||||
}
|
||||
|
||||
for (var lon = labelStart.Longitude; lon <= bounds.East; lon += lineDistance)
|
||||
{
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = projection.LocationToPoint(new Location(lineStart.Latitude, lon)),
|
||||
IsClosed = false,
|
||||
IsFilled = false
|
||||
};
|
||||
|
||||
figure.Segments.Add(new LineSegment
|
||||
{
|
||||
Point = projection.LocationToPoint(new Location(lineEnd.Latitude, lon)),
|
||||
});
|
||||
|
||||
geometry.Figures.Add(figure);
|
||||
}
|
||||
|
||||
var labelFormat = GetLabelFormat(lineDistance);
|
||||
var childIndex = 1; // 0 for Path
|
||||
|
||||
for (var lat = labelStart.Latitude; lat <= bounds.North; lat += lineDistance)
|
||||
{
|
||||
for (var lon = labelStart.Longitude; lon <= bounds.East; lon += lineDistance)
|
||||
{
|
||||
TextBlock label;
|
||||
|
||||
if (childIndex < Children.Count)
|
||||
{
|
||||
label = (TextBlock)Children[childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
var renderTransform = new TransformGroup();
|
||||
renderTransform.Children.Add(new TranslateTransform());
|
||||
renderTransform.Children.Add(ParentMap.RotateTransform);
|
||||
renderTransform.Children.Add(new TranslateTransform());
|
||||
|
||||
label = new TextBlock
|
||||
{
|
||||
RenderTransform = renderTransform
|
||||
};
|
||||
|
||||
label.SetBinding(TextBlock.ForegroundProperty,
|
||||
GetBindingExpression(ForegroundProperty)?.ParentBinding ??
|
||||
new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath("Foreground")
|
||||
});
|
||||
|
||||
Children.Add(label);
|
||||
}
|
||||
|
||||
childIndex++;
|
||||
|
||||
if (FontFamily != null)
|
||||
{
|
||||
label.FontFamily = FontFamily;
|
||||
}
|
||||
|
||||
label.FontSize = FontSize;
|
||||
label.FontStyle = FontStyle;
|
||||
label.FontStretch = FontStretch;
|
||||
label.FontWeight = FontWeight;
|
||||
label.Text = GetLabelText(lat, labelFormat, "NS") + "\n" + GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW");
|
||||
label.Tag = new Location(lat, lon);
|
||||
label.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
var translateTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[0];
|
||||
translateTransform.X = StrokeThickness / 2d + 2d;
|
||||
translateTransform.Y = -label.DesiredSize.Height / 2d;
|
||||
}
|
||||
}
|
||||
|
||||
while (Children.Count > childIndex)
|
||||
{
|
||||
Children.RemoveAt(Children.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// don't use MapPanel.Location because labels may be at more than 180° distance from map center
|
||||
|
||||
for (int i = 1; i < Children.Count; i++)
|
||||
{
|
||||
var label = (TextBlock)Children[i];
|
||||
var location = (Location)label.Tag;
|
||||
var viewportTransform = (TranslateTransform)((TransformGroup)label.RenderTransform).Children[2];
|
||||
var viewportPosition = projection.LocationToViewportPoint(location);
|
||||
viewportTransform.X = viewportPosition.X;
|
||||
viewportTransform.Y = viewportPosition.Y;
|
||||
}
|
||||
}
|
||||
else if (path != null)
|
||||
{
|
||||
path = null;
|
||||
graticuleStart = null;
|
||||
graticuleEnd = null;
|
||||
|
||||
Children.Clear();
|
||||
}
|
||||
|
||||
base.OnViewportChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
MapControl/UWP/MapImageLayer.UWP.cs
Normal file
57
MapControl/UWP/MapImageLayer.UWP.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapImageLayer
|
||||
{
|
||||
protected void UpdateImage(Uri uri)
|
||||
{
|
||||
UpdateImage(uri != null ? new BitmapImage(uri) : null);
|
||||
}
|
||||
|
||||
protected void UpdateImage(BitmapSource bitmapSource)
|
||||
{
|
||||
SetTopImage(bitmapSource);
|
||||
|
||||
var bitmapImage = bitmapSource as BitmapImage;
|
||||
|
||||
if (bitmapImage != null)
|
||||
{
|
||||
bitmapImage.ImageOpened += BitmapImageOpened;
|
||||
bitmapImage.ImageFailed += BitmapImageFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwapImages();
|
||||
}
|
||||
}
|
||||
|
||||
private void BitmapImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var bitmapImage = (BitmapImage)sender;
|
||||
|
||||
bitmapImage.ImageOpened -= BitmapImageOpened;
|
||||
bitmapImage.ImageFailed -= BitmapImageFailed;
|
||||
|
||||
SwapImages();
|
||||
}
|
||||
|
||||
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
var bitmapImage = (BitmapImage)sender;
|
||||
|
||||
bitmapImage.ImageOpened -= BitmapImageOpened;
|
||||
bitmapImage.ImageFailed -= BitmapImageFailed;
|
||||
|
||||
((Image)Children[topImageIndex]).Source = null;
|
||||
SwapImages();
|
||||
}
|
||||
}
|
||||
}
|
||||
26
MapControl/UWP/MapItem.UWP.cs
Normal file
26
MapControl/UWP/MapItem.UWP.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Container class for an item in a MapItemsControl.
|
||||
/// </summary>
|
||||
public class MapItem : ListBoxItem
|
||||
{
|
||||
public MapItem()
|
||||
{
|
||||
DefaultStyleKey = typeof(MapItem);
|
||||
MapPanel.AddParentMapHandlers(this);
|
||||
}
|
||||
|
||||
public Location Location
|
||||
{
|
||||
get { return (Location)GetValue(MapPanel.LocationProperty); }
|
||||
set { SetValue(MapPanel.LocationProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
31
MapControl/UWP/MapItemsControl.UWP.cs
Normal file
31
MapControl/UWP/MapItemsControl.UWP.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages a collection of selectable items on a Map. Uses MapItem as item container class.
|
||||
/// </summary>
|
||||
public class MapItemsControl : ListBox
|
||||
{
|
||||
public MapItemsControl()
|
||||
{
|
||||
DefaultStyleKey = typeof(MapItemsControl);
|
||||
MapPanel.AddParentMapHandlers(this);
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
return new MapItem();
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
return item is MapItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
MapControl/UWP/MapOverlay.UWP.cs
Normal file
95
MapControl/UWP/MapOverlay.UWP.cs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.UI.Text;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapOverlay
|
||||
{
|
||||
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
|
||||
nameof(FontSize), typeof(double), typeof(MapOverlay), new PropertyMetadata(10d));
|
||||
|
||||
public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register(
|
||||
nameof(FontFamily), typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
|
||||
nameof(FontStyle), typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(FontStyle.Normal));
|
||||
|
||||
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
|
||||
nameof(FontStretch), typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(FontStretch.Normal));
|
||||
|
||||
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
|
||||
nameof(FontWeight), typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(FontWeights.Normal));
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||
nameof(Foreground), typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
|
||||
nameof(Stroke), typeof(Brush), typeof(MapOverlay), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
nameof(StrokeThickness), typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
||||
nameof(StrokeDashArray), typeof(DoubleCollection), typeof(MapOverlay), new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashOffsetProperty = DependencyProperty.Register(
|
||||
nameof(StrokeDashOffset), typeof(double), typeof(MapOverlay), new PropertyMetadata(0d));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashCapProperty = DependencyProperty.Register(
|
||||
nameof(StrokeDashCap), typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||
|
||||
public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register(
|
||||
nameof(StrokeStartLineCap), typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||
|
||||
public static readonly DependencyProperty StrokeEndLineCapProperty = DependencyProperty.Register(
|
||||
nameof(StrokeEndLineCap), typeof(PenLineCap), typeof(MapOverlay), new PropertyMetadata(PenLineCap.Flat));
|
||||
|
||||
public static readonly DependencyProperty StrokeLineJoinProperty = DependencyProperty.Register(
|
||||
nameof(StrokeLineJoin), typeof(PenLineJoin), typeof(MapOverlay), new PropertyMetadata(PenLineJoin.Miter));
|
||||
|
||||
public static readonly DependencyProperty StrokeMiterLimitProperty = DependencyProperty.Register(
|
||||
nameof(StrokeMiterLimit), typeof(double), typeof(MapOverlay), new PropertyMetadata(1d));
|
||||
|
||||
protected override void SetParentMapOverride(MapBase parentMap)
|
||||
{
|
||||
if (GetBindingExpression(ForegroundProperty) != null)
|
||||
{
|
||||
ClearValue(ForegroundProperty);
|
||||
}
|
||||
|
||||
if (GetBindingExpression(StrokeProperty) != null)
|
||||
{
|
||||
ClearValue(StrokeProperty);
|
||||
}
|
||||
|
||||
if (parentMap != null)
|
||||
{
|
||||
if (Foreground == null)
|
||||
{
|
||||
SetBinding(ForegroundProperty, new Binding
|
||||
{
|
||||
Source = parentMap,
|
||||
Path = new PropertyPath("Foreground")
|
||||
});
|
||||
}
|
||||
|
||||
if (Stroke == null)
|
||||
{
|
||||
SetBinding(StrokeProperty, new Binding
|
||||
{
|
||||
Source = parentMap,
|
||||
Path = new PropertyPath("Foreground")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
base.SetParentMapOverride(parentMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
MapControl/UWP/MapPanel.UWP.cs
Normal file
68
MapControl/UWP/MapPanel.UWP.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapPanel
|
||||
{
|
||||
public static readonly DependencyProperty ParentMapProperty = DependencyProperty.RegisterAttached(
|
||||
"ParentMap", typeof(MapBase), typeof(MapPanel), new PropertyMetadata(null, ParentMapPropertyChanged));
|
||||
|
||||
public MapPanel()
|
||||
{
|
||||
if (this is MapBase)
|
||||
{
|
||||
SetValue(ParentMapProperty, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddParentMapHandlers(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to work around missing property value inheritance in Silverlight and Windows Runtime.
|
||||
/// Adds Loaded and Unloaded event handlers to the specified FrameworkElement, which set and clear the
|
||||
/// value of the MapPanel.ParentMap attached property.
|
||||
/// </summary>
|
||||
public static void AddParentMapHandlers(FrameworkElement element)
|
||||
{
|
||||
element.Loaded += (s, e) => GetParentMap(element);
|
||||
element.Unloaded += (s, e) => element.ClearValue(ParentMapProperty);
|
||||
}
|
||||
|
||||
public static MapBase GetParentMap(UIElement element)
|
||||
{
|
||||
var parentMap = (MapBase)element.GetValue(ParentMapProperty);
|
||||
|
||||
if (parentMap == null && (parentMap = FindParentMap(element)) != null)
|
||||
{
|
||||
element.SetValue(ParentMapProperty, parentMap);
|
||||
}
|
||||
|
||||
return parentMap;
|
||||
}
|
||||
|
||||
private static MapBase FindParentMap(UIElement element)
|
||||
{
|
||||
MapBase parentMap = null;
|
||||
var parentElement = VisualTreeHelper.GetParent(element) as UIElement;
|
||||
|
||||
if (parentElement != null)
|
||||
{
|
||||
parentMap = parentElement as MapBase;
|
||||
|
||||
if (parentMap == null)
|
||||
{
|
||||
parentMap = GetParentMap(parentElement);
|
||||
}
|
||||
}
|
||||
|
||||
return parentMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
MapControl/UWP/MapPath.UWP.cs
Normal file
46
MapControl/UWP/MapPath.UWP.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapPath : Path
|
||||
{
|
||||
private Geometry data;
|
||||
|
||||
public MapPath()
|
||||
{
|
||||
MapPanel.AddParentMapHandlers(this);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (Stretch != Stretch.None)
|
||||
{
|
||||
Stretch = Stretch.None;
|
||||
}
|
||||
|
||||
// Workaround for missing PropertyChangedCallback for the Data property.
|
||||
if (data != Data)
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
data.ClearValue(Geometry.TransformProperty);
|
||||
}
|
||||
|
||||
data = Data;
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
data.Transform = viewportTransform;
|
||||
}
|
||||
}
|
||||
|
||||
return new Size();
|
||||
}
|
||||
}
|
||||
}
|
||||
61
MapControl/UWP/MapPolyline.UWP.cs
Normal file
61
MapControl/UWP/MapPolyline.UWP.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapPolyline
|
||||
{
|
||||
public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
|
||||
nameof(FillRule), typeof(FillRule), typeof(MapPolyline),
|
||||
new PropertyMetadata(FillRule.EvenOdd, (o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
|
||||
|
||||
|
||||
public MapPolyline()
|
||||
{
|
||||
Data = new PathGeometry();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the locations that define the polyline points.
|
||||
/// </summary>
|
||||
public IEnumerable<Location> Locations
|
||||
{
|
||||
get { return (IEnumerable<Location>)GetValue(LocationsProperty); }
|
||||
set { SetValue(LocationsProperty, value); }
|
||||
}
|
||||
|
||||
protected override void UpdateData()
|
||||
{
|
||||
var geometry = (PathGeometry)Data;
|
||||
geometry.Figures.Clear();
|
||||
|
||||
if (ParentMap != null && Locations != null && Locations.Any())
|
||||
{
|
||||
var points = Locations.Select(l => ParentMap.MapProjection.LocationToPoint(l));
|
||||
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = points.First(),
|
||||
IsClosed = IsClosed,
|
||||
IsFilled = IsClosed
|
||||
};
|
||||
|
||||
var segment = new PolyLineSegment();
|
||||
|
||||
foreach (var point in points.Skip(1))
|
||||
{
|
||||
segment.Points.Add(point);
|
||||
}
|
||||
|
||||
figure.Segments.Add(segment);
|
||||
geometry.Figures.Add(figure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
MapControl/UWP/MapTileLayer.UWP.cs
Normal file
19
MapControl/UWP/MapTileLayer.UWP.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.UI.Xaml.Markup;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
[ContentProperty(Name = "TileSource")]
|
||||
public partial class MapTileLayer
|
||||
{
|
||||
partial void Initialize()
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
|
||||
MapPanel.AddParentMapHandlers(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
MapControl/UWP/MatrixEx.UWP.cs
Normal file
87
MapControl/UWP/MatrixEx.UWP.cs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
internal static class MatrixEx
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in MapProjection and MapTileLayer.
|
||||
/// </summary>
|
||||
public static Matrix TranslateScaleRotateTranslate(
|
||||
double translation1X, double translation1Y,
|
||||
double scaleX, double scaleY, double rotationAngle,
|
||||
double translation2X, double translation2Y)
|
||||
{
|
||||
var matrix = new Matrix(
|
||||
scaleX, 0d, 0d, scaleY,
|
||||
scaleX * translation1X,
|
||||
scaleY * translation1Y);
|
||||
|
||||
if (rotationAngle != 0d)
|
||||
{
|
||||
rotationAngle = (rotationAngle % 360d) / 180d * Math.PI;
|
||||
|
||||
var cos = Math.Cos(rotationAngle);
|
||||
var sin = Math.Sin(rotationAngle);
|
||||
|
||||
matrix = new Matrix(
|
||||
matrix.M11 * cos - matrix.M12 * sin,
|
||||
matrix.M11 * sin + matrix.M12 * cos,
|
||||
matrix.M21 * cos - matrix.M22 * sin,
|
||||
matrix.M21 * sin + matrix.M22 * cos,
|
||||
cos * matrix.OffsetX - sin * matrix.OffsetY,
|
||||
sin * matrix.OffsetX + cos * matrix.OffsetY);
|
||||
}
|
||||
|
||||
matrix.OffsetX += translation2X;
|
||||
matrix.OffsetY += translation2Y;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
public static Matrix TranslateScaleRotateTranslate_(
|
||||
double translation1X, double translation1Y,
|
||||
double scaleX, double scaleY, double rotationAngle,
|
||||
double translation2X, double translation2Y)
|
||||
{
|
||||
var m11 = scaleX;
|
||||
var m12 = 0d;
|
||||
var m21 = 0d;
|
||||
var m22 = scaleY;
|
||||
var offsetX = scaleX * translation1X;
|
||||
var offsetY = scaleY * translation1Y;
|
||||
|
||||
if (rotationAngle != 0d)
|
||||
{
|
||||
rotationAngle = (rotationAngle % 360d) / 180d * Math.PI;
|
||||
|
||||
var cos = Math.Cos(rotationAngle);
|
||||
var sin = Math.Sin(rotationAngle);
|
||||
|
||||
var _m11 = m11;
|
||||
var _m12 = m12;
|
||||
var _m21 = m21;
|
||||
var _m22 = m22;
|
||||
var _offsetX = offsetX;
|
||||
var _offsetY = offsetY;
|
||||
|
||||
m11 = _m11 * cos - _m12 * sin;
|
||||
m12 = _m11 * sin + _m12 * cos;
|
||||
m21 = _m21 * cos - _m22 * sin;
|
||||
m22 = _m21 * sin + _m22 * cos;
|
||||
offsetX = cos * _offsetX - sin * _offsetY;
|
||||
offsetY = sin * _offsetX + cos * _offsetY;
|
||||
}
|
||||
|
||||
offsetX += translation2X;
|
||||
offsetY += translation2Y;
|
||||
|
||||
return new Matrix(m11, m12, m21, m22, offsetX, offsetY);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
MapControl/UWP/Properties/AssemblyInfo.cs
Normal file
14
MapControl/UWP/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("XAML Map Control for UWP")]
|
||||
[assembly: AssemblyDescription("XAML Map Control Library for UWP")]
|
||||
[assembly: AssemblyProduct("XAML Map Control")]
|
||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyVersion("4.0.0")]
|
||||
[assembly: AssemblyFileVersion("4.0.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
5
MapControl/UWP/Properties/MapControl.UWP.rd.xml
Normal file
5
MapControl/UWP/Properties/MapControl.UWP.rd.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Library Name="MapControl.UWP">
|
||||
</Library>
|
||||
</Directives>
|
||||
26
MapControl/UWP/Pushpin.UWP.cs
Normal file
26
MapControl/UWP/Pushpin.UWP.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays a pushpin at a geographic location provided by the MapPanel.Location attached property.
|
||||
/// </summary>
|
||||
public class Pushpin : ContentControl
|
||||
{
|
||||
public Pushpin()
|
||||
{
|
||||
DefaultStyleKey = typeof(Pushpin);
|
||||
MapPanel.AddParentMapHandlers(this);
|
||||
}
|
||||
|
||||
public Location Location
|
||||
{
|
||||
get { return (Location)GetValue(MapPanel.LocationProperty); }
|
||||
set { SetValue(MapPanel.LocationProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
65
MapControl/UWP/Themes/Generic.xaml
Normal file
65
MapControl/UWP/Themes/Generic.xaml
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:map="using:MapControl">
|
||||
<Style TargetType="map:MapItemsControl">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<ItemsPresenter/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<map:MapPanel/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style TargetType="map:MapItem">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="map:MapItem">
|
||||
<ContentPresenter Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style TargetType="map:Pushpin">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Padding" Value="3"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="map:Pushpin">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle Fill="{TemplateBinding Background}"/>
|
||||
<Path Grid.Row="1" Fill="{TemplateBinding Background}" Data="M 0,-0.5 L 0,16 16,-0.5"/>
|
||||
<ContentPresenter Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
64
MapControl/UWP/Tile.UWP.cs
Normal file
64
MapControl/UWP/Tile.UWP.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class Tile
|
||||
{
|
||||
public void SetImage(ImageSource imageSource, bool fadeIn = true)
|
||||
{
|
||||
Pending = false;
|
||||
|
||||
if (fadeIn && FadeDuration > TimeSpan.Zero)
|
||||
{
|
||||
var bitmapImage = imageSource as BitmapImage;
|
||||
|
||||
if (bitmapImage != null && bitmapImage.UriSource != null)
|
||||
{
|
||||
bitmapImage.ImageOpened += BitmapImageOpened;
|
||||
bitmapImage.ImageFailed += BitmapImageFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
Image.BeginAnimation(UIElement.OpacityProperty,
|
||||
new DoubleAnimation { From = 0d, To = 1d, Duration = FadeDuration });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Image.Opacity = 1d;
|
||||
}
|
||||
|
||||
Image.Source = imageSource;
|
||||
}
|
||||
|
||||
private void BitmapImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var bitmapImage = (BitmapImage)sender;
|
||||
|
||||
bitmapImage.ImageOpened -= BitmapImageOpened;
|
||||
bitmapImage.ImageFailed -= BitmapImageFailed;
|
||||
|
||||
Image.BeginAnimation(UIElement.OpacityProperty,
|
||||
new DoubleAnimation { From = 0d, To = 1d, Duration = FadeDuration });
|
||||
}
|
||||
|
||||
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
var bitmapImage = (BitmapImage)sender;
|
||||
|
||||
bitmapImage.ImageOpened -= BitmapImageOpened;
|
||||
bitmapImage.ImageFailed -= BitmapImageFailed;
|
||||
|
||||
Image.Source = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
MapControl/UWP/TileImageLoader.UWP.cs
Normal file
114
MapControl/UWP/TileImageLoader.UWP.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.Web.Http;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class TileImageLoader : ITileImageLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// Default StorageFolder where an IImageCache instance may save cached data.
|
||||
/// </summary>
|
||||
public static readonly StorageFolder DefaultCacheFolder = ApplicationData.Current.TemporaryFolder;
|
||||
|
||||
/// <summary>
|
||||
/// The IImageCache implementation used to cache tile images. The default is null.
|
||||
/// </summary>
|
||||
public static Caching.IImageCache Cache { get; set; }
|
||||
|
||||
private async Task LoadTileImageAsync(Tile tile, Uri uri, string cacheKey)
|
||||
{
|
||||
var cacheItem = await Cache.GetAsync(cacheKey);
|
||||
var buffer = cacheItem?.Buffer;
|
||||
var loaded = false;
|
||||
|
||||
//if (buffer != null)
|
||||
//{
|
||||
// Debug.WriteLine("TileImageLoader: {0}: expire{1} {2}", cacheKey, cacheItem.Expiration < DateTime.UtcNow ? "d" : "s", cacheItem.Expiration);
|
||||
//}
|
||||
|
||||
if (buffer == null || cacheItem.Expiration < DateTime.UtcNow)
|
||||
{
|
||||
loaded = await DownloadTileImageAsync(tile, uri, cacheKey);
|
||||
}
|
||||
|
||||
if (!loaded && buffer != null) // keep expired image if download failed
|
||||
{
|
||||
await SetTileImageAsync(tile, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> DownloadTileImageAsync(Tile tile, Uri uri, string cacheKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var response = await HttpClient.GetAsync(uri))
|
||||
{
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
string tileInfo;
|
||||
|
||||
if (!response.Headers.TryGetValue(bingMapsTileInfo, out tileInfo) ||
|
||||
tileInfo != bingMapsNoTile)
|
||||
{
|
||||
var buffer = await response.Content.ReadAsBufferAsync();
|
||||
|
||||
await SetTileImageAsync(tile, buffer); // create BitmapImage in UI thread before caching
|
||||
|
||||
await Cache.SetAsync(cacheKey, buffer, GetExpiration(response));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.WriteLine("TileImageLoader: {0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("TileImageLoader: {0}: {1}", uri, ex.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task SetTileImageAsync(Tile tile, IBuffer buffer)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
using (var stream = new InMemoryRandomAccessStream())
|
||||
{
|
||||
await stream.WriteAsync(buffer);
|
||||
await stream.FlushAsync(); // necessary?
|
||||
stream.Seek(0);
|
||||
|
||||
await tile.Image.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var bitmapImage = new BitmapImage();
|
||||
await bitmapImage.SetSourceAsync(stream);
|
||||
|
||||
tile.SetImage(bitmapImage);
|
||||
tcs.SetResult(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.SetException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
MapControl/UWP/project.json
Normal file
16
MapControl/UWP/project.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"uap10.0": {}
|
||||
},
|
||||
"runtimes": {
|
||||
"win10-arm": {},
|
||||
"win10-arm-aot": {},
|
||||
"win10-x86": {},
|
||||
"win10-x86-aot": {},
|
||||
"win10-x64": {},
|
||||
"win10-x64-aot": {}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue