mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-04-05 14:37:01 +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
274
MapControl/WPF/ImageFileCache.WPF.cs
Normal file
274
MapControl/WPF/ImageFileCache.WPF.cs
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Caching;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace MapControl.Caching
|
||||
{
|
||||
/// <summary>
|
||||
/// ObjectCache implementation based on local image files.
|
||||
/// The only valid data type for cached values is byte[].
|
||||
/// </summary>
|
||||
public class ImageFileCache : ObjectCache
|
||||
{
|
||||
private static readonly FileSystemAccessRule fullControlRule = new FileSystemAccessRule(
|
||||
new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
|
||||
FileSystemRights.FullControl, AccessControlType.Allow);
|
||||
|
||||
private readonly MemoryCache memoryCache = MemoryCache.Default;
|
||||
private readonly string rootFolder;
|
||||
|
||||
public ImageFileCache(string rootFolder)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rootFolder))
|
||||
{
|
||||
throw new ArgumentException("The parameter rootFolder must not be null or empty.");
|
||||
}
|
||||
|
||||
this.rootFolder = rootFolder;
|
||||
|
||||
Debug.WriteLine("Created ImageFileCache in " + rootFolder);
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return string.Empty; }
|
||||
}
|
||||
|
||||
public override DefaultCacheCapabilities DefaultCacheCapabilities
|
||||
{
|
||||
get { return DefaultCacheCapabilities.None; }
|
||||
}
|
||||
|
||||
public override object this[string key]
|
||||
{
|
||||
get { return Get(key); }
|
||||
set { Set(key, value, null); }
|
||||
}
|
||||
|
||||
protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
throw new NotSupportedException("ImageFileCache does not support the ability to enumerate items.");
|
||||
}
|
||||
|
||||
public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable<string> keys, string regionName = null)
|
||||
{
|
||||
throw new NotSupportedException("ImageFileCache does not support the ability to create change monitors.");
|
||||
}
|
||||
|
||||
public override long GetCount(string regionName = null)
|
||||
{
|
||||
throw new NotSupportedException("ImageFileCache does not support the ability to count items.");
|
||||
}
|
||||
|
||||
public override bool Contains(string key, string regionName = null)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException("The parameter key must not be null.");
|
||||
}
|
||||
|
||||
if (regionName != null)
|
||||
{
|
||||
throw new NotSupportedException("The parameter regionName must be null.");
|
||||
}
|
||||
|
||||
return memoryCache.Contains(key) || FindFile(key) != null;
|
||||
}
|
||||
|
||||
public override object Get(string key, string regionName = null)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException("The parameter key must not be null.");
|
||||
}
|
||||
|
||||
if (regionName != null)
|
||||
{
|
||||
throw new NotSupportedException("The parameter regionName must be null.");
|
||||
}
|
||||
|
||||
var buffer = memoryCache.Get(key) as byte[];
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
var path = FindFile(key);
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.WriteLine("ImageFileCache: Reading " + path);
|
||||
buffer = File.ReadAllBytes(path);
|
||||
memoryCache.Set(key, buffer, new CacheItemPolicy());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Failed reading {0}: {1}", path, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public override CacheItem GetCacheItem(string key, string regionName = null)
|
||||
{
|
||||
var value = Get(key, regionName);
|
||||
|
||||
return value != null ? new CacheItem(key, value) : null;
|
||||
}
|
||||
|
||||
public override IDictionary<string, object> GetValues(IEnumerable<string> keys, string regionName = null)
|
||||
{
|
||||
return keys.ToDictionary(key => key, key => Get(key, regionName));
|
||||
}
|
||||
|
||||
public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException("The parameter key must not be null.");
|
||||
}
|
||||
|
||||
if (regionName != null)
|
||||
{
|
||||
throw new NotSupportedException("The parameter regionName must be null.");
|
||||
}
|
||||
|
||||
var buffer = value as byte[];
|
||||
|
||||
if (buffer == null || buffer.Length == 0)
|
||||
{
|
||||
throw new NotSupportedException("The parameter value must be a non-empty byte array.");
|
||||
}
|
||||
|
||||
memoryCache.Set(key, buffer, policy);
|
||||
|
||||
var path = GetPath(key);
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", path, policy.AbsoluteExpiration.DateTime.ToLocalTime());
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
File.WriteAllBytes(path, buffer);
|
||||
|
||||
var fileSecurity = File.GetAccessControl(path);
|
||||
fileSecurity.AddAccessRule(fullControlRule);
|
||||
File.SetAccessControl(path, fileSecurity);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Failed writing {0}: {1}", path, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
|
||||
{
|
||||
Set(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
|
||||
}
|
||||
|
||||
public override void Set(CacheItem item, CacheItemPolicy policy)
|
||||
{
|
||||
Set(item.Key, item.Value, policy, item.RegionName);
|
||||
}
|
||||
|
||||
public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
|
||||
{
|
||||
var oldValue = Get(key, regionName);
|
||||
|
||||
Set(key, value, policy);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
|
||||
{
|
||||
return AddOrGetExisting(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
|
||||
}
|
||||
|
||||
public override CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
|
||||
{
|
||||
var oldItem = GetCacheItem(item.Key, item.RegionName);
|
||||
|
||||
Set(item, policy);
|
||||
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
public override object Remove(string key, string regionName = null)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException("The parameter key must not be null.");
|
||||
}
|
||||
|
||||
if (regionName != null)
|
||||
{
|
||||
throw new NotSupportedException("The parameter regionName must be null.");
|
||||
}
|
||||
|
||||
memoryCache.Remove(key);
|
||||
|
||||
var path = FindFile(key);
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Failed removing {0}: {1}", path, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string FindFile(string key)
|
||||
{
|
||||
var path = GetPath(key);
|
||||
|
||||
try
|
||||
{
|
||||
if (path != null && File.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Failed finding {0}: {1}", path, ex.Message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetPath(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Path.Combine(rootFolder, Path.Combine(key.Split('\\', '/', ':', ';')));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("ImageFileCache: Invalid key {0}/{1}: {2}", rootFolder, key, ex.Message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
MapControl/WPF/Map.WPF.cs
Normal file
103
MapControl/WPF/Map.WPF.cs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// MapBase with default input event handling.
|
||||
/// </summary>
|
||||
public class Map : MapBase
|
||||
{
|
||||
public static readonly DependencyProperty ManipulationModeProperty = DependencyProperty.Register(
|
||||
nameof(ManipulationMode), typeof(ManipulationModes), typeof(Map), new PropertyMetadata(ManipulationModes.All));
|
||||
|
||||
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
|
||||
nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d));
|
||||
|
||||
private Point? mousePosition;
|
||||
|
||||
static Map()
|
||||
{
|
||||
IsManipulationEnabledProperty.OverrideMetadata(typeof(Map), new FrameworkPropertyMetadata(true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that specifies how the map control handles manipulations.
|
||||
/// </summary>
|
||||
public ManipulationModes ManipulationMode
|
||||
{
|
||||
get { return (ManipulationModes)GetValue(ManipulationModeProperty); }
|
||||
set { SetValue(ManipulationModeProperty, value); }
|
||||
}
|
||||
|
||||
/// <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 override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
var zoomDelta = MouseWheelZoomDelta * e.Delta / 120d;
|
||||
ZoomMap(e.GetPosition(this), TargetZoomLevel + zoomDelta);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
|
||||
if (CaptureMouse())
|
||||
{
|
||||
mousePosition = e.GetPosition(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonUp(e);
|
||||
|
||||
if (mousePosition.HasValue)
|
||||
{
|
||||
mousePosition = null;
|
||||
ReleaseMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (mousePosition.HasValue)
|
||||
{
|
||||
var position = e.GetPosition(this);
|
||||
TranslateMap(position - mousePosition.Value);
|
||||
mousePosition = position;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
|
||||
{
|
||||
base.OnManipulationStarted(e);
|
||||
|
||||
Manipulation.SetManipulationMode(this, ManipulationMode);
|
||||
}
|
||||
|
||||
protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
|
||||
{
|
||||
base.OnManipulationDelta(e);
|
||||
|
||||
TransformMap(e.ManipulationOrigin,
|
||||
e.DeltaManipulation.Translation, e.DeltaManipulation.Rotation,
|
||||
(e.DeltaManipulation.Scale.X + e.DeltaManipulation.Scale.Y) / 2d);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
MapControl/WPF/MapBase.WPF.cs
Normal file
83
MapControl/WPF/MapBase.WPF.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapBase
|
||||
{
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
Control.ForegroundProperty.AddOwner(typeof(MapBase));
|
||||
|
||||
public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
|
||||
nameof(Center), typeof(Location), typeof(MapBase), new FrameworkPropertyMetadata(
|
||||
new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((MapBase)o).CenterPropertyChanged((Location)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty TargetCenterProperty = DependencyProperty.Register(
|
||||
nameof(TargetCenter), typeof(Location), typeof(MapBase), new FrameworkPropertyMetadata(
|
||||
new Location(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((MapBase)o).TargetCenterPropertyChanged((Location)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelProperty = DependencyProperty.Register(
|
||||
nameof(ZoomLevel), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
|
||||
1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((MapBase)o).ZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty TargetZoomLevelProperty = DependencyProperty.Register(
|
||||
nameof(TargetZoomLevel), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
|
||||
1d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((MapBase)o).TargetZoomLevelPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
|
||||
nameof(Heading), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
|
||||
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((MapBase)o).HeadingPropertyChanged((double)e.NewValue)));
|
||||
|
||||
public static readonly DependencyProperty TargetHeadingProperty = DependencyProperty.Register(
|
||||
nameof(TargetHeading), typeof(double), typeof(MapBase), new FrameworkPropertyMetadata(
|
||||
0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(o, e) => ((MapBase)o).TargetHeadingPropertyChanged((double)e.NewValue)));
|
||||
|
||||
static MapBase()
|
||||
{
|
||||
ClipToBoundsProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(true));
|
||||
BackgroundProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
|
||||
}
|
||||
|
||||
partial void RemoveAnimation(DependencyProperty property)
|
||||
{
|
||||
BeginAnimation(property, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Center property according to the specified translation in viewport coordinates.
|
||||
/// </summary>
|
||||
public void TranslateMap(Vector translation)
|
||||
{
|
||||
TranslateMap((Point)translation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Center, Heading and ZoomLevel properties according to the specified
|
||||
/// viewport coordinate translation, rotation and scale delta values. Rotation and scaling
|
||||
/// is performed relative to the specified center point in viewport coordinates.
|
||||
/// </summary>
|
||||
public void TransformMap(Point center, Vector translation, double rotation, double scale)
|
||||
{
|
||||
TransformMap(center, (Point)translation, rotation, scale);
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
|
||||
ResetTransformCenter();
|
||||
UpdateTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
183
MapControl/WPF/MapControl.WPF.csproj
Normal file
183
MapControl/WPF/MapControl.WPF.csproj
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<?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>{A204A102-C745-4D65-AEC8-7B96FAEDEF2D}</ProjectGuid>
|
||||
<OutputType>library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MapControl</RootNamespace>
|
||||
<AssemblyName>MapControl.WPF</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Runtime.Caching" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Themes\Generic.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</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="ImageFileCache.WPF.cs" />
|
||||
<Compile Include="Map.WPF.cs" />
|
||||
<Compile Include="MapBase.WPF.cs" />
|
||||
<Compile Include="MapGraticule.WPF.cs" />
|
||||
<Compile Include="MapImageLayer.WPF.cs" />
|
||||
<Compile Include="MapItem.WPF.cs" />
|
||||
<Compile Include="MapItemsControl.WPF.cs" />
|
||||
<Compile Include="MapOverlay.WPF.cs" />
|
||||
<Compile Include="MapPanel.WPF.cs" />
|
||||
<Compile Include="MapPath.WPF.cs" />
|
||||
<Compile Include="MapPolyline.WPF.cs" />
|
||||
<Compile Include="MapScale.WPF.cs" />
|
||||
<Compile Include="MapTileLayer.WPF.cs" />
|
||||
<Compile Include="Pushpin.WPF.cs" />
|
||||
<Compile Include="TileImageLoader.WPF.cs" />
|
||||
<Compile Include="TypeConverters.WPF.cs" />
|
||||
<Compile Include="MatrixEx.WPF.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Tile.WPF.cs" />
|
||||
<Compile Include="XmlDocument.WPF.cs" />
|
||||
<None Include="..\..\MapControl.snk">
|
||||
<Link>MapControl.snk</Link>
|
||||
</None>
|
||||
<AppDesigner Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.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>
|
||||
91
MapControl/WPF/MapGraticule.WPF.cs
Normal file
91
MapControl/WPF/MapGraticule.WPF.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapGraticule
|
||||
{
|
||||
private class Label
|
||||
{
|
||||
public readonly double Position;
|
||||
public readonly FormattedText Text;
|
||||
|
||||
public Label(double position, FormattedText text)
|
||||
{
|
||||
Position = position;
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
static MapGraticule()
|
||||
{
|
||||
IsHitTestVisibleProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(false));
|
||||
StrokeThicknessProperty.OverrideMetadata(typeof(MapGraticule), new FrameworkPropertyMetadata(0.5));
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
var projection = ParentMap?.MapProjection;
|
||||
|
||||
if (projection != null && !double.IsNaN(projection.LongitudeScale))
|
||||
{
|
||||
var bounds = projection.ViewportRectToBoundingBox(new Rect(ParentMap.RenderSize));
|
||||
var lineDistance = GetLineDistance();
|
||||
var labelFormat = GetLabelFormat(lineDistance);
|
||||
var latLabelStart = Math.Ceiling(bounds.South / lineDistance) * lineDistance;
|
||||
var lonLabelStart = Math.Ceiling(bounds.West / lineDistance) * lineDistance;
|
||||
var latLabels = new List<Label>((int)((bounds.North - latLabelStart) / lineDistance) + 1);
|
||||
var lonLabels = new List<Label>((int)((bounds.East - lonLabelStart) / lineDistance) + 1);
|
||||
|
||||
for (var lat = latLabelStart; lat <= bounds.North; lat += lineDistance)
|
||||
{
|
||||
latLabels.Add(new Label(lat, new FormattedText(
|
||||
GetLabelText(lat, labelFormat, "NS"),
|
||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
|
||||
|
||||
drawingContext.DrawLine(Pen,
|
||||
projection.LocationToViewportPoint(new Location(lat, bounds.West)),
|
||||
projection.LocationToViewportPoint(new Location(lat, bounds.East)));
|
||||
}
|
||||
|
||||
for (var lon = lonLabelStart; lon <= bounds.East; lon += lineDistance)
|
||||
{
|
||||
lonLabels.Add(new Label(lon, new FormattedText(
|
||||
GetLabelText(Location.NormalizeLongitude(lon), labelFormat, "EW"),
|
||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground)));
|
||||
|
||||
drawingContext.DrawLine(Pen,
|
||||
projection.LocationToViewportPoint(new Location(bounds.South, lon)),
|
||||
projection.LocationToViewportPoint(new Location(bounds.North, lon)));
|
||||
}
|
||||
|
||||
foreach (var latLabel in latLabels)
|
||||
{
|
||||
foreach (var lonLabel in lonLabels)
|
||||
{
|
||||
var position = projection.LocationToViewportPoint(new Location(latLabel.Position, lonLabel.Position));
|
||||
|
||||
drawingContext.PushTransform(new RotateTransform(ParentMap.Heading, position.X, position.Y));
|
||||
drawingContext.DrawText(latLabel.Text,
|
||||
new Point(position.X + StrokeThickness / 2d + 2d, position.Y - StrokeThickness / 2d - latLabel.Text.Height));
|
||||
drawingContext.DrawText(lonLabel.Text,
|
||||
new Point(position.X + StrokeThickness / 2d + 2d, position.Y + StrokeThickness / 2d));
|
||||
drawingContext.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
MapControl/WPF/MapImageLayer.WPF.cs
Normal file
57
MapControl/WPF/MapImageLayer.WPF.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 System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapImageLayer
|
||||
{
|
||||
protected void UpdateImage(Uri uri)
|
||||
{
|
||||
UpdateImage(uri != null
|
||||
? BitmapFrame.Create(uri, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnDemand)
|
||||
: null);
|
||||
}
|
||||
|
||||
protected void UpdateImage(BitmapSource bitmapSource)
|
||||
{
|
||||
SetTopImage(bitmapSource);
|
||||
|
||||
if (bitmapSource != null && !bitmapSource.IsFrozen && bitmapSource.IsDownloading)
|
||||
{
|
||||
bitmapSource.DownloadCompleted += BitmapDownloadCompleted;
|
||||
bitmapSource.DownloadFailed += BitmapDownloadFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwapImages();
|
||||
}
|
||||
}
|
||||
|
||||
private void BitmapDownloadCompleted(object sender, EventArgs e)
|
||||
{
|
||||
var bitmapSource = (BitmapSource)sender;
|
||||
|
||||
bitmapSource.DownloadCompleted -= BitmapDownloadCompleted;
|
||||
bitmapSource.DownloadFailed -= BitmapDownloadFailed;
|
||||
|
||||
SwapImages();
|
||||
}
|
||||
|
||||
private void BitmapDownloadFailed(object sender, ExceptionEventArgs e)
|
||||
{
|
||||
var bitmapSource = (BitmapSource)sender;
|
||||
|
||||
bitmapSource.DownloadCompleted -= BitmapDownloadCompleted;
|
||||
bitmapSource.DownloadFailed -= BitmapDownloadFailed;
|
||||
|
||||
((Image)Children[topImageIndex]).Source = null;
|
||||
SwapImages();
|
||||
}
|
||||
}
|
||||
}
|
||||
28
MapControl/WPF/MapItem.WPF.cs
Normal file
28
MapControl/WPF/MapItem.WPF.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Container class for an item in a MapItemsControl.
|
||||
/// </summary>
|
||||
public class MapItem : ListBoxItem
|
||||
{
|
||||
static MapItem()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LocationProperty = MapPanel.LocationProperty.AddOwner(typeof(MapItem));
|
||||
|
||||
public Location Location
|
||||
{
|
||||
get { return (Location)GetValue(LocationProperty); }
|
||||
set { SetValue(LocationProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
30
MapControl/WPF/MapItemsControl.WPF.cs
Normal file
30
MapControl/WPF/MapItemsControl.WPF.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages a collection of selectable items on a Map. Uses MapItem as item container class.
|
||||
/// </summary>
|
||||
public class MapItemsControl : ListBox
|
||||
{
|
||||
static MapItemsControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(MapItemsControl), new FrameworkPropertyMetadata(typeof(MapItemsControl)));
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
return new MapItem();
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
return item is MapItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
100
MapControl/WPF/MapOverlay.WPF.cs
Normal file
100
MapControl/WPF/MapOverlay.WPF.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class 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) => { if (o.GetValue(StrokeProperty) == null) ((MapOverlay)o).pen = null; }));
|
||||
|
||||
public static readonly DependencyProperty StrokeProperty = Shape.StrokeProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = Shape.StrokeThicknessProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = Shape.StrokeDashArrayProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashOffsetProperty = Shape.StrokeDashOffsetProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeDashCapProperty = Shape.StrokeDashCapProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeStartLineCapProperty = Shape.StrokeStartLineCapProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeEndLineCapProperty = Shape.StrokeEndLineCapProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeLineJoinProperty = Shape.StrokeLineJoinProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
|
||||
typeof(MapOverlay), new FrameworkPropertyMetadata((o, e) => ((MapOverlay)o).pen = null));
|
||||
|
||||
private Typeface typeface;
|
||||
private Pen pen;
|
||||
|
||||
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 ?? Foreground,
|
||||
Thickness = StrokeThickness,
|
||||
DashStyle = new DashStyle(StrokeDashArray, StrokeDashOffset),
|
||||
DashCap = StrokeDashCap,
|
||||
StartLineCap = StrokeStartLineCap,
|
||||
EndLineCap = StrokeEndLineCap,
|
||||
LineJoin = StrokeLineJoin,
|
||||
MiterLimit = StrokeMiterLimit
|
||||
};
|
||||
|
||||
pen.Freeze();
|
||||
}
|
||||
|
||||
return pen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
MapControl/WPF/MapPanel.WPF.cs
Normal file
30
MapControl/WPF/MapPanel.WPF.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapPanel
|
||||
{
|
||||
private static readonly DependencyPropertyKey ParentMapPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
|
||||
"ParentMap", typeof(MapBase), typeof(MapPanel),
|
||||
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty ParentMapProperty = ParentMapPropertyKey.DependencyProperty;
|
||||
|
||||
public MapPanel()
|
||||
{
|
||||
if (this is MapBase)
|
||||
{
|
||||
SetValue(ParentMapPropertyKey, this);
|
||||
}
|
||||
}
|
||||
|
||||
public static MapBase GetParentMap(UIElement element)
|
||||
{
|
||||
return (MapBase)element.GetValue(ParentMapProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
MapControl/WPF/MapPath.WPF.cs
Normal file
64
MapControl/WPF/MapPath.WPF.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.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapPath : Shape
|
||||
{
|
||||
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
|
||||
nameof(Data), typeof(Geometry), typeof(MapPath), new FrameworkPropertyMetadata(
|
||||
null, FrameworkPropertyMetadataOptions.AffectsRender, DataPropertyChanged, CoerceDataProperty));
|
||||
|
||||
static MapPath()
|
||||
{
|
||||
StretchProperty.OverrideMetadata(typeof(MapPath),
|
||||
new FrameworkPropertyMetadata { CoerceValueCallback = (o, v) => Stretch.None });
|
||||
}
|
||||
|
||||
public Geometry Data
|
||||
{
|
||||
get { return (Geometry)GetValue(DataProperty); }
|
||||
set { SetValue(DataProperty, value); }
|
||||
}
|
||||
|
||||
protected override Geometry DefiningGeometry
|
||||
{
|
||||
get { return Data; }
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
return new Size();
|
||||
}
|
||||
|
||||
private static void DataPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (!ReferenceEquals(e.OldValue, e.NewValue))
|
||||
{
|
||||
var mapPath = (MapPath)obj;
|
||||
|
||||
if (e.OldValue != null)
|
||||
{
|
||||
((Geometry)e.OldValue).ClearValue(Geometry.TransformProperty);
|
||||
}
|
||||
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
((Geometry)e.NewValue).Transform = mapPath.viewportTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static object CoerceDataProperty(DependencyObject obj, object value)
|
||||
{
|
||||
var data = (Geometry)value;
|
||||
|
||||
return (data != null && data.IsFrozen) ? data.CloneCurrentValue() : data;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
MapControl/WPF/MapPolyline.WPF.cs
Normal file
55
MapControl/WPF/MapPolyline.WPF.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// 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.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class MapPolyline
|
||||
{
|
||||
public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
|
||||
nameof(FillRule), typeof(FillRule), typeof(MapPolyline), new FrameworkPropertyMetadata(
|
||||
FillRule.EvenOdd, FrameworkPropertyMetadataOptions.AffectsRender,
|
||||
(o, e) => ((StreamGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
|
||||
|
||||
public MapPolyline()
|
||||
{
|
||||
Data = new StreamGeometry();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the locations that define the polyline points.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(LocationCollectionConverter))]
|
||||
public IEnumerable<Location> Locations
|
||||
{
|
||||
get { return (IEnumerable<Location>)GetValue(LocationsProperty); }
|
||||
set { SetValue(LocationsProperty, value); }
|
||||
}
|
||||
|
||||
protected override void UpdateData()
|
||||
{
|
||||
var geometry = (StreamGeometry)Data;
|
||||
|
||||
if (ParentMap != null && Locations != null && Locations.Any())
|
||||
{
|
||||
using (var context = geometry.Open())
|
||||
{
|
||||
var points = Locations.Select(l => ParentMap.MapProjection.LocationToPoint(l));
|
||||
|
||||
context.BeginFigure(points.First(), IsClosed, IsClosed);
|
||||
context.PolyLineTo(points.Skip(1).ToList(), true, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
geometry.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
MapControl/WPF/MapScale.WPF.cs
Normal file
96
MapControl/WPF/MapScale.WPF.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// 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.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws a map scale overlay.
|
||||
/// </summary>
|
||||
public class MapScale : MapOverlay
|
||||
{
|
||||
public static readonly DependencyProperty PaddingProperty = Control.PaddingProperty.AddOwner(
|
||||
typeof(MapScale), new FrameworkPropertyMetadata(new Thickness(2d)));
|
||||
|
||||
private double length;
|
||||
private Size size;
|
||||
|
||||
static MapScale()
|
||||
{
|
||||
IsHitTestVisibleProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(false));
|
||||
MinWidthProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(100d));
|
||||
HorizontalAlignmentProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(HorizontalAlignment.Right));
|
||||
VerticalAlignmentProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(VerticalAlignment.Bottom));
|
||||
StrokeStartLineCapProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
||||
StrokeEndLineCapProperty.OverrideMetadata(typeof(MapScale), new FrameworkPropertyMetadata(PenLineCap.Round));
|
||||
}
|
||||
|
||||
public Thickness Padding
|
||||
{
|
||||
get { return (Thickness)GetValue(PaddingProperty); }
|
||||
set { SetValue(PaddingProperty, value); }
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (ParentMap != null && ParentMap.ScaleTransform.ScaleX > 0d)
|
||||
{
|
||||
length = MinWidth / ParentMap.ScaleTransform.ScaleX;
|
||||
var magnitude = Math.Pow(10d, Math.Floor(Math.Log10(length)));
|
||||
|
||||
if (length / magnitude < 2d)
|
||||
{
|
||||
length = 2d * magnitude;
|
||||
}
|
||||
else if (length / magnitude < 5d)
|
||||
{
|
||||
length = 5d * magnitude;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 10d * magnitude;
|
||||
}
|
||||
|
||||
size.Width = length * ParentMap.ScaleTransform.ScaleX + StrokeThickness + Padding.Left + Padding.Right;
|
||||
size.Height = FontSize * FontFamily.LineSpacing + StrokeThickness + Padding.Top + Padding.Bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
size.Width = size.Height = 0d;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
if (ParentMap != null)
|
||||
{
|
||||
var x1 = Padding.Left + StrokeThickness / 2d;
|
||||
var x2 = size.Width - Padding.Right - StrokeThickness / 2d;
|
||||
var y1 = size.Height / 2d;
|
||||
var y2 = size.Height - Padding.Bottom - StrokeThickness / 2d;
|
||||
var text = new FormattedText(
|
||||
length >= 1000d ? string.Format("{0:0} km", length / 1000d) : string.Format("{0:0} m", length),
|
||||
CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface, FontSize, Foreground);
|
||||
|
||||
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(x2, y1), new Point(x2, y2));
|
||||
drawingContext.DrawLine(Pen, new Point(x1, y2), new Point(x2, y2));
|
||||
drawingContext.DrawText(text, new Point((size.Width - text.Width) / 2d, 0d));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||
{
|
||||
InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
}
|
||||
18
MapControl/WPF/MapTileLayer.WPF.cs
Normal file
18
MapControl/WPF/MapTileLayer.WPF.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
[ContentProperty("TileSource")]
|
||||
public partial class MapTileLayer
|
||||
{
|
||||
static MapTileLayer()
|
||||
{
|
||||
IsHitTestVisibleProperty.OverrideMetadata(typeof(MapTileLayer), new FrameworkPropertyMetadata(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
26
MapControl/WPF/MatrixEx.WPF.cs
Normal file
26
MapControl/WPF/MatrixEx.WPF.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 System.Windows.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(1d, 0d, 0d, 1d, translation1X, translation1Y);
|
||||
matrix.Scale(scaleX, scaleY);
|
||||
matrix.Rotate(rotationAngle);
|
||||
matrix.Translate(translation2X, translation2Y);
|
||||
return matrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
MapControl/WPF/Properties/AssemblyInfo.cs
Normal file
16
MapControl/WPF/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
[assembly: AssemblyTitle("XAML Map Control for WPF")]
|
||||
[assembly: AssemblyDescription("XAML Map Control Library for WPF")]
|
||||
[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)]
|
||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||
29
MapControl/WPF/Pushpin.WPF.cs
Normal file
29
MapControl/WPF/Pushpin.WPF.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
||||
// © 2017 Clemens Fischer
|
||||
// Licensed under the Microsoft Public License (Ms-PL)
|
||||
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays a pushpin at a geographic location provided by the MapPanel.Location attached property.
|
||||
/// </summary>
|
||||
public class Pushpin : ContentControl
|
||||
{
|
||||
static Pushpin()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Pushpin), new FrameworkPropertyMetadata(typeof(Pushpin)));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LocationProperty =
|
||||
MapPanel.LocationProperty.AddOwner(typeof(Pushpin));
|
||||
|
||||
public Location Location
|
||||
{
|
||||
get { return (Location)GetValue(LocationProperty); }
|
||||
set { SetValue(LocationProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
65
MapControl/WPF/Themes/Generic.xaml
Normal file
65
MapControl/WPF/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="clr-namespace: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/WPF/Tile.WPF.cs
Normal file
64
MapControl/WPF/Tile.WPF.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 System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class Tile
|
||||
{
|
||||
public void SetImage(ImageSource imageSource, bool fadeIn = true)
|
||||
{
|
||||
Pending = false;
|
||||
|
||||
if (fadeIn && FadeDuration > TimeSpan.Zero)
|
||||
{
|
||||
var bitmapSource = imageSource as BitmapSource;
|
||||
|
||||
if (bitmapSource != null && !bitmapSource.IsFrozen && bitmapSource.IsDownloading)
|
||||
{
|
||||
bitmapSource.DownloadCompleted += BitmapDownloadCompleted;
|
||||
bitmapSource.DownloadFailed += BitmapDownloadFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
Image.BeginAnimation(UIElement.OpacityProperty,
|
||||
new DoubleAnimation(0d, 1d, FadeDuration));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Image.Opacity = 1d;
|
||||
}
|
||||
|
||||
Image.Source = imageSource;
|
||||
}
|
||||
|
||||
private void BitmapDownloadCompleted(object sender, EventArgs e)
|
||||
{
|
||||
var bitmapSource = (BitmapSource)sender;
|
||||
|
||||
bitmapSource.DownloadCompleted -= BitmapDownloadCompleted;
|
||||
bitmapSource.DownloadFailed -= BitmapDownloadFailed;
|
||||
|
||||
Image.BeginAnimation(UIElement.OpacityProperty,
|
||||
new DoubleAnimation(0d, 1d, FadeDuration));
|
||||
}
|
||||
|
||||
private void BitmapDownloadFailed(object sender, ExceptionEventArgs e)
|
||||
{
|
||||
var bitmapSource = (BitmapSource)sender;
|
||||
|
||||
bitmapSource.DownloadCompleted -= BitmapDownloadCompleted;
|
||||
bitmapSource.DownloadFailed -= BitmapDownloadFailed;
|
||||
|
||||
Image.Source = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
127
MapControl/WPF/TileImageLoader.WPF.cs
Normal file
127
MapControl/WPF/TileImageLoader.WPF.cs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.Caching;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public partial class TileImageLoader : ITileImageLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// Default folder path where an ObjectCache instance may save cached data.
|
||||
/// </summary>
|
||||
public static readonly string DefaultCacheFolder =
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl", "TileCache");
|
||||
|
||||
/// <summary>
|
||||
/// The ObjectCache used to cache tile images. The default is MemoryCache.Default.
|
||||
/// </summary>
|
||||
public static ObjectCache Cache { get; set; } = MemoryCache.Default;
|
||||
|
||||
private async Task LoadTileImageAsync(Tile tile, Uri uri, string cacheKey)
|
||||
{
|
||||
DateTime expiration;
|
||||
var buffer = GetCachedImage(cacheKey, out expiration);
|
||||
var loaded = false;
|
||||
|
||||
//if (buffer != null)
|
||||
//{
|
||||
// Debug.WriteLine("TileImageLoader: {0}: expire{1} {2}", cacheKey, expiration < DateTime.UtcNow ? "d" : "s", expiration);
|
||||
//}
|
||||
|
||||
if (buffer == null || expiration < DateTime.UtcNow)
|
||||
{
|
||||
loaded = await DownloadTileImageAsync(tile, uri, cacheKey);
|
||||
}
|
||||
|
||||
if (!loaded && buffer != null) // keep expired image if download failed
|
||||
{
|
||||
using (var stream = new MemoryStream(buffer))
|
||||
{
|
||||
await SetTileImageAsync(tile, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> DownloadTileImageAsync(Tile tile, Uri uri, string cacheKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var response = await HttpClient.GetAsync(uri))
|
||||
{
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
IEnumerable<string> tileInfo;
|
||||
|
||||
if (!response.Headers.TryGetValues(bingMapsTileInfo, out tileInfo) ||
|
||||
!tileInfo.Contains(bingMapsNoTile))
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
await response.Content.CopyToAsync(stream);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
await SetTileImageAsync(tile, stream); // create BitmapFrame in UI thread before caching
|
||||
|
||||
SetCachedImage(cacheKey, stream, 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, MemoryStream stream)
|
||||
{
|
||||
var imageSource = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
|
||||
await tile.Image.Dispatcher.InvokeAsync(() => tile.SetImage(imageSource));
|
||||
}
|
||||
|
||||
private static byte[] GetCachedImage(string cacheKey, out DateTime expiration)
|
||||
{
|
||||
var buffer = Cache.Get(cacheKey) as byte[];
|
||||
|
||||
if (buffer != null && buffer.Length >= 16 &&
|
||||
Encoding.ASCII.GetString(buffer, buffer.Length - 16, 8) == "EXPIRES:")
|
||||
{
|
||||
expiration = new DateTime(BitConverter.ToInt64(buffer, buffer.Length - 8), DateTimeKind.Utc);
|
||||
}
|
||||
else
|
||||
{
|
||||
expiration = DateTime.MinValue;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static void SetCachedImage(string cacheKey, MemoryStream stream, DateTime expiration)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.End);
|
||||
stream.Write(Encoding.ASCII.GetBytes("EXPIRES:"), 0, 8);
|
||||
stream.Write(BitConverter.GetBytes(expiration.Ticks), 0, 8);
|
||||
|
||||
Cache.Set(cacheKey, stream.ToArray(), new CacheItemPolicy { AbsoluteExpiration = expiration });
|
||||
}
|
||||
}
|
||||
}
|
||||
84
MapControl/WPF/TypeConverters.WPF.cs
Normal file
84
MapControl/WPF/TypeConverters.WPF.cs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// 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.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public class LocationConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
return Location.Parse((string)value);
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(LocationConverter))]
|
||||
[Serializable]
|
||||
public partial class Location
|
||||
{
|
||||
}
|
||||
|
||||
public class LocationCollectionConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
return LocationCollection.Parse((string)value);
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(LocationCollectionConverter))]
|
||||
public partial class LocationCollection
|
||||
{
|
||||
}
|
||||
|
||||
public class BoundingBoxConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
return BoundingBox.Parse((string)value);
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(BoundingBoxConverter))]
|
||||
[Serializable]
|
||||
public partial class BoundingBox
|
||||
{
|
||||
}
|
||||
|
||||
public class TileSourceConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
return new TileSource { UriFormat = value as string };
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(TileSourceConverter))]
|
||||
public partial class TileSource
|
||||
{
|
||||
}
|
||||
}
|
||||
24
MapControl/WPF/XmlDocument.WPF.cs
Normal file
24
MapControl/WPF/XmlDocument.WPF.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
|
||||
#pragma warning disable CS1998 // async method lacks await operators and will run synchronously
|
||||
|
||||
namespace MapControl
|
||||
{
|
||||
public class XmlDocument : System.Xml.XmlDocument
|
||||
{
|
||||
public static Task<XmlDocument> LoadFromUriAsync(Uri uri)
|
||||
{
|
||||
return Task.Run(async () => // without async, debugger may stop on unhandled exception from XmlDocument.Load
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.Load(uri.ToString());
|
||||
return document;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue