Version 4.1.

This commit is contained in:
ClemensF 2017-09-05 20:57:17 +02:00
parent ef6d1ed959
commit 467d82ead7
25 changed files with 323 additions and 309 deletions

View file

@ -5,11 +5,14 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace MapControl
{
public partial class MapBase
{
private const FillBehavior AnimationFillBehavior = FillBehavior.Stop;
public static readonly DependencyProperty ForegroundProperty =
Control.ForegroundProperty.AddOwner(typeof(MapBase));
@ -49,9 +52,11 @@ namespace MapControl
BackgroundProperty.OverrideMetadata(typeof(MapBase), new FrameworkPropertyMetadata(Brushes.Transparent));
}
partial void RemoveAnimation(DependencyProperty property)
public MapBase()
{
BeginAnimation(property, null);
MapProjection = new WebMercatorProjection();
ScaleRotateTransform.Children.Add(ScaleTransform);
ScaleRotateTransform.Children.Add(RotateTransform);
}
/// <summary>

View file

@ -23,6 +23,8 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>
</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@ -99,6 +101,9 @@
<Compile Include="..\Shared\MapImageLayer.cs">
<Link>MapImageLayer.cs</Link>
</Compile>
<Compile Include="..\Shared\MapItemsControl.cs">
<Link>MapItemsControl.cs</Link>
</Compile>
<Compile Include="..\Shared\MapOverlay.cs">
<Link>MapOverlay.cs</Link>
</Compile>
@ -123,6 +128,9 @@
<Compile Include="..\Shared\OrthographicProjection.cs">
<Link>OrthographicProjection.cs</Link>
</Compile>
<Compile Include="..\Shared\Pushpin.cs">
<Link>Pushpin.cs</Link>
</Compile>
<Compile Include="..\Shared\StereographicProjection.cs">
<Link>StereographicProjection.cs</Link>
</Compile>
@ -152,15 +160,12 @@
<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="MapTileLayer.WPF.cs" />
<Compile Include="Pushpin.WPF.cs" />
<Compile Include="TileImageLoader.WPF.cs" />
<Compile Include="TileSource.WPF.cs" />
<Compile Include="TypeConverters.WPF.cs" />
<Compile Include="MatrixEx.WPF.cs" />
<Compile Include="Properties\AssemblyInfo.cs">

View file

@ -1,28 +0,0 @@
// 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); }
}
}
}

View file

@ -1,30 +0,0 @@
// 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;
}
}
}

View file

@ -51,7 +51,7 @@ namespace MapControl
public static readonly DependencyProperty StrokeMiterLimitProperty = Shape.StrokeMiterLimitProperty.AddOwner(
typeof(MapOverlay), new FrameworkPropertyMetadata { AffectsRender = true });
protected override void SetParentMapOverride(MapBase parentMap)
protected override void SetParentMap(MapBase parentMap)
{
if (GetBindingExpression(StrokeProperty) != null)
{
@ -67,7 +67,7 @@ namespace MapControl
});
}
base.SetParentMapOverride(parentMap);
base.SetParentMap(parentMap);
}
}
}

View file

@ -14,17 +14,17 @@ namespace MapControl
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);
}
public static void InitMapElement(FrameworkElement element)
{
if (element is MapBase)
{
element.SetValue(ParentMapPropertyKey, element);
}
}
}
}

View file

@ -1,29 +0,0 @@
// 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); }
}
}
}

View file

@ -3,11 +3,8 @@
// 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;
@ -34,11 +31,6 @@ namespace MapControl
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);
@ -55,32 +47,31 @@ namespace MapControl
private async Task<bool> DownloadTileImageAsync(Tile tile, Uri uri, string cacheKey)
{
var success = false;
try
{
using (var response = await HttpClient.GetAsync(uri))
using (var response = await TileSource.HttpClient.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
success = response.IsSuccessStatusCode;
if (!success)
{
IEnumerable<string> tileInfo;
if (!response.Headers.TryGetValues(bingMapsTileInfo, out tileInfo) ||
!tileInfo.Contains(bingMapsNoTile))
Debug.WriteLine("TileImageLoader: {0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase);
}
else if (TileSource.TileAvailable(response.Headers))
{
using (var stream = new MemoryStream())
{
using (var stream = new MemoryStream())
{
await response.Content.CopyToAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
await response.Content.CopyToAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
await SetTileImageAsync(tile, stream); // create BitmapFrame in UI thread before caching
await SetTileImageAsync(tile, stream); // create BitmapFrame before caching
SetCachedImage(cacheKey, stream, GetExpiration(response));
}
SetCachedImage(cacheKey, stream, GetExpiration(response));
}
return true;
}
Debug.WriteLine("TileImageLoader: {0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase);
}
}
catch (Exception ex)
@ -88,7 +79,7 @@ namespace MapControl
Debug.WriteLine("TileImageLoader: {0}: {1}", uri, ex.Message);
}
return false;
return success;
}
private async Task SetTileImageAsync(Tile tile, MemoryStream stream)

View file

@ -0,0 +1,82 @@
// 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.Net.Http.Headers;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MapControl
{
public partial class TileSource
{
/// <summary>
/// The HttpClient instance used when image data is downloaded from a web resource.
/// </summary>
public static HttpClient HttpClient { get; set; } = new HttpClient();
/// <summary>
/// Check HTTP response headers for tile unavailability, e.g. X-VE-Tile-Info=no-tile
/// </summary>
public static bool TileAvailable(HttpResponseHeaders responseHeaders)
{
IEnumerable<string> tileInfo;
return !responseHeaders.TryGetValues("X-VE-Tile-Info", out tileInfo) || !tileInfo.Contains("no-tile");
}
/// <summary>
/// Load a tile ImageSource asynchronously from GetUri(x, y, zoomLevel)
/// </summary>
public virtual async Task<ImageSource> LoadImageAsync(int x, int y, int zoomLevel)
{
ImageSource imageSource = null;
var uri = GetUri(x, y, zoomLevel);
if (uri != null)
{
try
{
if (uri.Scheme == "http")
{
using (var response = await HttpClient.GetAsync(uri))
{
if (!response.IsSuccessStatusCode)
{
Debug.WriteLine("TileSource: {0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase);
}
else if (TileAvailable(response.Headers))
{
using (var stream = new MemoryStream())
{
await response.Content.CopyToAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
imageSource = await Task.Run(() => BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad));
}
}
}
}
else
{
imageSource = BitmapFrame.Create(uri, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
catch (Exception ex)
{
Debug.WriteLine("TileSource: {0}: {1}", uri, ex.Message);
}
}
return imageSource;
}
}
}