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

@ -76,18 +76,6 @@ namespace MapControl
private double centerLongitude;
private bool internalPropertyChange;
public MapBase()
{
Initialize();
MapProjection = new WebMercatorProjection();
ScaleRotateTransform.Children.Add(ScaleTransform);
ScaleRotateTransform.Children.Add(RotateTransform);
}
partial void Initialize(); // Windows Runtime and Silverlight only
partial void RemoveAnimation(DependencyProperty property); // WPF only
/// <summary>
/// Raised when the current viewport has changed.
/// </summary>
@ -504,7 +492,8 @@ namespace MapControl
targetCenter.Latitude,
Location.NearestLongitude(targetCenter.Longitude, Center.Longitude))),
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction
EasingFunction = AnimationEasingFunction,
FillBehavior = AnimationFillBehavior
};
centerAnimation.Completed += CenterAnimationCompleted;
@ -522,7 +511,6 @@ namespace MapControl
InternalSetValue(CenterProperty, TargetCenter);
InternalSetValue(CenterPointProperty, MapProjection.LocationToPoint(TargetCenter));
RemoveAnimation(CenterPointProperty); // remove holding animation in WPF
UpdateTransform();
}
}
@ -607,7 +595,8 @@ namespace MapControl
{
To = targetZoomLevel,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction
EasingFunction = AnimationEasingFunction,
FillBehavior = AnimationFillBehavior
};
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
@ -624,8 +613,6 @@ namespace MapControl
zoomLevelAnimation = null;
InternalSetValue(ZoomLevelProperty, TargetZoomLevel);
RemoveAnimation(ZoomLevelProperty); // remove holding animation in WPF
UpdateTransform(true);
}
}
@ -681,7 +668,8 @@ namespace MapControl
{
By = delta,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction
EasingFunction = AnimationEasingFunction,
FillBehavior = AnimationFillBehavior
};
headingAnimation.Completed += HeadingAnimationCompleted;
@ -698,7 +686,6 @@ namespace MapControl
headingAnimation = null;
InternalSetValue(HeadingProperty, TargetHeading);
RemoveAnimation(HeadingProperty); // remove holding animation in WPF
UpdateTransform();
}
}

View file

@ -0,0 +1,50 @@
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if WINDOWS_UWP
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#else
using System.Windows;
using System.Windows.Controls;
#endif
namespace MapControl
{
/// <summary>
/// Container class for an item in a MapItemsControl.
/// </summary>
public class MapItem : ListBoxItem
{
public MapItem()
{
DefaultStyleKey = typeof(MapItem);
MapPanel.InitMapElement(this);
}
}
/// <summary>
/// Manages a collection of selectable items on a Map.
/// </summary>
public class MapItemsControl : ListBox
{
public MapItemsControl()
{
DefaultStyleKey = typeof(MapItemsControl);
MapPanel.InitMapElement(this);
}
protected override DependencyObject GetContainerForItemOverride()
{
return new MapItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is MapItem;
}
}
}

View file

@ -16,6 +16,10 @@ using System.Windows.Media;
namespace MapControl
{
/// <summary>
/// Optional interface to hold the value of the MapPanel.ParentMap attached property.
/// May be used to get notified when the property value changes.
/// </summary>
public interface IMapElement
{
MapBase ParentMap { get; set; }
@ -35,6 +39,13 @@ namespace MapControl
public static readonly DependencyProperty BoundingBoxProperty = DependencyProperty.RegisterAttached(
"BoundingBox", typeof(BoundingBox), typeof(MapPanel), new PropertyMetadata(null, BoundingBoxPropertyChanged));
private MapBase parentMap;
public MapPanel()
{
InitMapElement(this);
}
public static Location GetLocation(UIElement element)
{
return (Location)element.GetValue(LocationProperty);
@ -55,12 +66,10 @@ namespace MapControl
element.SetValue(BoundingBoxProperty, value);
}
private MapBase parentMap;
public MapBase ParentMap
{
get { return parentMap; }
set { SetParentMapOverride(value); }
set { SetParentMap(value); }
}
protected override Size MeasureOverride(Size availableSize)
@ -101,7 +110,7 @@ namespace MapControl
return finalSize;
}
protected virtual void SetParentMapOverride(MapBase map)
protected virtual void SetParentMap(MapBase map)
{
if (parentMap != null && parentMap != this)
{

View file

@ -24,6 +24,11 @@ namespace MapControl
nameof(Location), typeof(Location), typeof(MapPath),
new PropertyMetadata(null, (o, e) => ((MapPath)o).LocationPropertyChanged()));
public MapPath()
{
MapPanel.InitMapElement(this);
}
public Location Location
{
get { return (Location)GetValue(LocationProperty); }

View file

@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
#if WINDOWS_UWP
using Windows.Foundation;
using Windows.UI.Xaml;
@ -21,13 +22,13 @@ namespace MapControl
{
public interface ITileImageLoader
{
void LoadTiles(MapTileLayer tileLayer);
Task LoadTilesAsync(MapTileLayer tileLayer);
}
/// <summary>
/// Fills the map viewport with map tiles from a TileSource.
/// </summary>
public partial class MapTileLayer : Panel, IMapLayer
public class MapTileLayer : Panel, IMapLayer
{
/// <summary>
/// A default MapTileLayer using OpenStreetMap data.
@ -66,9 +67,6 @@ namespace MapControl
public static readonly DependencyProperty MaxZoomLevelProperty = DependencyProperty.Register(
nameof(MaxZoomLevel), typeof(int), typeof(MapTileLayer), new PropertyMetadata(18));
public static readonly DependencyProperty MaxParallelDownloadsProperty = DependencyProperty.Register(
nameof(MaxParallelDownloads), typeof(int), typeof(MapTileLayer), new PropertyMetadata(4));
public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(
nameof(UpdateInterval), typeof(TimeSpan), typeof(MapTileLayer),
new PropertyMetadata(TimeSpan.FromSeconds(0.2), (o, e) => ((MapTileLayer)o).updateTimer.Interval = (TimeSpan)e.NewValue));
@ -92,17 +90,16 @@ namespace MapControl
public MapTileLayer(ITileImageLoader tileImageLoader)
{
Initialize();
IsHitTestVisible = false;
RenderTransform = new MatrixTransform();
TileImageLoader = tileImageLoader;
Tiles = new List<Tile>();
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
updateTimer.Tick += (s, e) => UpdateTileGrid();
}
partial void Initialize(); // Windows Runtime and Silverlight only
MapPanel.InitMapElement(this);
}
public ITileImageLoader TileImageLoader { get; private set; }
public ICollection<Tile> Tiles { get; private set; }
@ -162,15 +159,6 @@ namespace MapControl
set { SetValue(MaxZoomLevelProperty, value); }
}
/// <summary>
/// Maximum number of parallel downloads that may be performed by the MapTileLayer's ITileImageLoader.
/// </summary>
public int MaxParallelDownloads
{
get { return (int)GetValue(MaxParallelDownloadsProperty); }
set { SetValue(MaxParallelDownloadsProperty, value); }
}
/// <summary>
/// Minimum time interval between tile updates.
/// </summary>
@ -400,7 +388,7 @@ namespace MapControl
Children.Add(tile.Image);
}
TileImageLoader.LoadTiles(this);
var task = TileImageLoader.LoadTilesAsync(this);
}
}
}

View file

@ -0,0 +1,25 @@
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if WINDOWS_UWP
using Windows.UI.Xaml.Controls;
#else
using System.Windows.Controls;
#endif
namespace MapControl
{
/// <summary>
/// Pushpin at a geographic location specified by the MapPanel.Location attached property.
/// </summary>
public class Pushpin : ContentControl
{
public Pushpin()
{
DefaultStyleKey = typeof(Pushpin);
MapPanel.InitMapElement(this);
}
}
}

View file

@ -7,6 +7,7 @@ using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
#if WINDOWS_UWP
@ -22,11 +23,6 @@ namespace MapControl
/// </summary>
public partial class TileImageLoader : ITileImageLoader
{
/// <summary>
/// The HttpClient instance used when image data is downloaded from a web resource.
/// </summary>
public static HttpClient HttpClient { get; set; } = new HttpClient();
/// <summary>
/// Default expiration time for cached tile images. Used when no expiration time
/// was transmitted on download. The default value is one day.
@ -50,13 +46,10 @@ namespace MapControl
/// </summary>
public static string CacheKeyFormat { get; set; } = "{0};{1};{2};{3}{4}";
private const string bingMapsTileInfo = "X-VE-Tile-Info";
private const string bingMapsNoTile = "no-tile";
private readonly ConcurrentStack<Tile> pendingTiles = new ConcurrentStack<Tile>();
private int taskCount;
public void LoadTiles(MapTileLayer tileLayer)
public async Task LoadTilesAsync(MapTileLayer tileLayer)
{
pendingTiles.Clear();
@ -69,18 +62,18 @@ namespace MapControl
if (Cache == null || string.IsNullOrEmpty(sourceName) ||
tileSource.UriFormat == null || !tileSource.UriFormat.StartsWith("http"))
{
// no caching, load tile images in UI thread
// no caching, load tile images directly
foreach (var tile in tiles)
{
LoadTileImage(tileSource, tile);
await LoadTileImageAsync(tileSource, tile);
}
}
else
{
pendingTiles.PushRange(tiles.Reverse().ToArray());
while (taskCount < Math.Min(pendingTiles.Count, tileLayer.MaxParallelDownloads))
while (taskCount < Math.Min(pendingTiles.Count, ServicePointManager.DefaultConnectionLimit))
{
Interlocked.Increment(ref taskCount);
@ -95,13 +88,13 @@ namespace MapControl
}
}
private void LoadTileImage(TileSource tileSource, Tile tile)
private async Task LoadTileImageAsync(TileSource tileSource, Tile tile)
{
tile.Pending = false;
try
{
var imageSource = tileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
var imageSource = await tileSource.LoadImageAsync(tile.XIndex, tile.Y, tile.ZoomLevel);
if (imageSource != null)
{

View file

@ -4,13 +4,6 @@
using System;
using System.Globalization;
#if WINDOWS_UWP
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows.Media;
using System.Windows.Media.Imaging;
#endif
namespace MapControl
{
@ -92,17 +85,6 @@ namespace MapControl
return getUri?.Invoke(x, y, zoomLevel);
}
/// <summary>
/// Gets the map tile ImageSource without caching in TileImageLoader.Cache.
/// By overriding LoadImage an application can provide arbitrary tile images.
/// </summary>
public virtual ImageSource LoadImage(int x, int y, int zoomLevel)
{
var uri = GetUri(x, y, zoomLevel);
return uri != null ? new BitmapImage(uri) : null;
}
private Uri GetBasicUri(int x, int y, int zoomLevel)
{
return new Uri(uriFormat