Version 2.7.0.

- WPF TileImageLoader reverted to caching byte arrays instead of BitmapFrames.
- Uses FileDb version 6.1.
This commit is contained in:
ClemensF 2015-11-28 21:09:25 +01:00
parent bc30e1d9ca
commit 5adcd6568e
32 changed files with 336 additions and 300 deletions

View file

@ -18,6 +18,9 @@ using System.Windows.Media.Imaging;
namespace MapControl
{
/// <summary>
/// Displays Bing Maps tiles. The static ApiKey property must be set to a Bing Maps API Key.
/// </summary>
public class BingMapsTileLayer : TileLayer
{
public enum MapMode
@ -26,6 +29,12 @@ namespace MapControl
}
public BingMapsTileLayer()
: this(new TileImageLoader())
{
}
public BingMapsTileLayer(ITileImageLoader tileImageLoader)
: base(tileImageLoader)
{
MinZoomLevel = 1;
MaxZoomLevel = 21;
@ -43,7 +52,7 @@ namespace MapControl
if (string.IsNullOrEmpty(ApiKey))
{
throw new InvalidOperationException("A Bing Maps API Key must be assigned to the ApiKey property.");
throw new InvalidOperationException("BingMapsTileLayer requires a Bing Maps API Key.");
}
var uri = string.Format("http://dev.virtualearth.net/REST/V1/Imagery/Metadata/{0}?output=xml&key={1}", Mode, ApiKey);

View file

@ -8,7 +8,7 @@ namespace MapControl
{
internal class BingMapsTileSource : TileSource
{
private string[] subdomains;
private readonly string[] subdomains;
public BingMapsTileSource(string uriFormat, string[] subdomains)
: base(uriFormat)

View file

@ -8,7 +8,7 @@ using System.Windows.Input;
namespace MapControl
{
/// <summary>
/// Default input event handling.
/// MapBase with default input event handling.
/// </summary>
public class Map : MapBase
{

View file

@ -8,7 +8,7 @@ using System.Windows.Input;
namespace MapControl
{
/// <summary>
/// Default input event handling.
/// MapBase with default input event handling.
/// </summary>
public class Map : MapBase
{

View file

@ -10,7 +10,7 @@ using Windows.UI.Xaml.Input;
namespace MapControl
{
/// <summary>
/// Default input event handling.
/// MapBase with default input event handling.
/// </summary>
public class Map : MapBase
{

View file

@ -21,7 +21,7 @@ using System.Windows.Media.Animation;
namespace MapControl
{
/// <summary>
/// The map control. Renders map content provided by the TileLayer or TileLayers property.
/// The map control. Displays map content provided by the TileLayer or TileLayers property.
/// The visible map area is defined by the Center and ZoomLevel properties.
/// The map can be rotated by an angle that is given by the Heading property.
/// MapBase can contain map overlay child elements like other MapPanels or MapItemsControls.

View file

@ -14,8 +14,8 @@ using System.Windows;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyVersion("2.7.0")]
[assembly: AssemblyFileVersion("2.7.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -11,6 +11,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Caching;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
@ -197,7 +198,7 @@ namespace MapControl
}
catch (Exception ex)
{
Debug.WriteLine("Loading tile image failed: {0}", (object)ex.Message);
Debug.WriteLine("ImageTileSource.LoadImage: " + ex.Message);
}
return image;
@ -218,7 +219,7 @@ namespace MapControl
}
catch (Exception ex)
{
Debug.WriteLine("Creating tile image failed: {0}", (object)ex.Message);
Debug.WriteLine("{0}: {1}", path, ex.Message);
}
}
@ -232,7 +233,11 @@ namespace MapControl
try
{
var request = HttpWebRequest.CreateHttp(uri);
request.UserAgent = HttpUserAgent;
if (HttpUserAgent != null)
{
request.UserAgent = HttpUserAgent;
}
using (var response = (HttpWebResponse)request.GetResponse())
{
@ -240,23 +245,24 @@ namespace MapControl
using (var memoryStream = new MemoryStream())
{
responseStream.CopyTo(memoryStream);
memoryStream.Position = 0;
image = BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
memoryStream.Seek(0, SeekOrigin.Begin);
if (cacheKey != null)
{
SetCachedImage(cacheKey, image, GetExpiration(response.Headers));
image = BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
if (cacheKey != null)
{
SetCachedImage(cacheKey, memoryStream, GetExpiration(response.Headers));
}
}
}
}
catch (WebException ex)
{
Debug.WriteLine("Downloading {0} failed: {1}: {2}", uri, ex.Status, ex.Message);
Debug.WriteLine("{0}: {1}: {2}", uri, ex.Status, ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("Downloading {0} failed: {1}", uri, ex.Message);
Debug.WriteLine("{0}: {1}", uri, ex.Message);
}
return image;
@ -274,34 +280,44 @@ namespace MapControl
private static bool GetCachedImage(string cacheKey, out BitmapSource image)
{
image = Cache.Get(cacheKey) as BitmapSource;
image = null;
if (image == null)
var buffer = Cache.Get(cacheKey) as byte[];
if (buffer != null)
{
return false;
try
{
using (var memoryStream = new MemoryStream(buffer))
{
image = BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
DateTime expiration = DateTime.MinValue;
if (buffer.Length >= 16 && Encoding.ASCII.GetString(buffer, buffer.Length - 16, 8) == "EXPIRES:")
{
expiration = new DateTime(BitConverter.ToInt64(buffer, buffer.Length - 8), DateTimeKind.Utc);
}
return expiration > DateTime.UtcNow;
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", cacheKey, ex.Message);
}
}
var metadata = (BitmapMetadata)image.Metadata;
DateTime expiration;
// get cache expiration date from BitmapMetadata.DateTaken, must be parsed with CurrentCulture
return metadata == null
|| metadata.DateTaken == null
|| !DateTime.TryParse(metadata.DateTaken, CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out expiration)
|| expiration > DateTime.UtcNow;
return false;
}
private static void SetCachedImage(string cacheKey, BitmapSource image, DateTime expiration)
private static void SetCachedImage(string cacheKey, MemoryStream memoryStream, DateTime expiration)
{
var bitmap = BitmapFrame.Create(image);
var metadata = (BitmapMetadata)bitmap.Metadata;
memoryStream.Seek(0, SeekOrigin.End);
memoryStream.Write(Encoding.ASCII.GetBytes("EXPIRES:"), 0, 8);
memoryStream.Write(BitConverter.GetBytes(expiration.Ticks), 0, 8);
// store cache expiration date in BitmapMetadata.DateTaken
metadata.DateTaken = expiration.ToString(CultureInfo.InvariantCulture);
metadata.Freeze();
bitmap.Freeze();
Cache.Set(cacheKey, bitmap, new CacheItemPolicy { AbsoluteExpiration = expiration });
Cache.Set(cacheKey, memoryStream.ToArray(), new CacheItemPolicy { AbsoluteExpiration = expiration });
//Debug.WriteLine("Cached {0}, Expires {1}", cacheKey, expiration);
}

View file

@ -20,7 +20,7 @@ using System.Windows.Threading;
namespace MapControl
{
/// <summary>
/// Fills a rectangular area with map tiles from a TileSource.
/// Fills the map viewport with map tiles from a TileSource.
/// </summary>
#if NETFX_CORE
[ContentProperty(Name = "TileSource")]

View file

@ -153,7 +153,7 @@ namespace MapControl
}
return new Uri(uriFormat
.Replace("{i}", new string(quadkey[zoomLevel - 1], 1))
.Replace("{i}", new string(quadkey, zoomLevel - 1, 1))
.Replace("{q}", new string(quadkey)),
UriKind.RelativeOrAbsolute);
}

View file

@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.6.0")]
[assembly: AssemblyFileVersion("2.6.0")]
[assembly: AssemblyVersion("2.7.0")]
[assembly: AssemblyFileVersion("2.7.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]