mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Version 2.7.0.
- WPF TileImageLoader reverted to caching byte arrays instead of BitmapFrames. - Uses FileDb version 6.1.
This commit is contained in:
parent
bc30e1d9ca
commit
5adcd6568e
Binary file not shown.
|
|
@ -6,8 +6,10 @@
|
||||||
<members>
|
<members>
|
||||||
<member name="T:FileDbNs.FileDb">
|
<member name="T:FileDbNs.FileDb">
|
||||||
<summary>
|
<summary>
|
||||||
Represents an open FileDb database file. None of the FileDb classes are re-entrant -
|
Represents an open FileDb database file. All of the FileDb classes/methods are re-entrant -
|
||||||
access to the class objects must be syncronised by the calling application.
|
there is no need to syncronise access to the class objects by the calling application.
|
||||||
|
However you should use the try-finally pattern when you open a FileDb to ensure
|
||||||
|
prompt closing in the finally code block.
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
|
|
@ -503,34 +505,39 @@
|
||||||
<param name="fieldName">The name of the Field to rename</param>
|
<param name="fieldName">The name of the Field to rename</param>
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FileDbNs.FileDb.SetEncryptionKey(System.String)">
|
<member name="M:FileDbNs.FileDb.SetEncryptor(FileDbNs.IEncryptor)">
|
||||||
<summary>
|
<summary>
|
||||||
|
Used to set your own encryptor. Use this for cross-platform encryption scenarios, where you
|
||||||
|
have control over the encryption method being used. See the Windows Sample apps for an example.
|
||||||
|
</summary>
|
||||||
|
<param name="encryptor"></param>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.FileDb.EncryptString(System.String)">
|
||||||
|
<summary>
|
||||||
|
Convienience method to encrypt a string value. You must first call SetEncryptor with an Encryptor.
|
||||||
|
</summary>
|
||||||
|
<param name="value">The string to encrypt</param>
|
||||||
|
<returns>The encrypted value</returns>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.FileDb.DecryptString(System.String)">
|
||||||
|
<summary>
|
||||||
|
Decrypt a string value. You must first call SetEncryptor with an Encryptor.
|
||||||
|
</summary>
|
||||||
|
<param name="value">The string to decrypt</param>
|
||||||
|
<returns>The decrypted value</returns>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.FileDb.SetEncryptionKey(System.String,System.String)">
|
||||||
|
<summary>
|
||||||
|
*** Only works on Windows platform. Use SetEncryptor to provide your own encryptor for cross platform databases ***
|
||||||
|
*** Do not use this method anymore ***
|
||||||
Allows you to set an encryption key after the database has been opened. You must set
|
Allows you to set an encryption key after the database has been opened. You must set
|
||||||
the encryption key before reading or writing to the database. Encryption is "all or nothing",
|
the encryption key before reading or writing to the database. Encryption is "all or nothing",
|
||||||
meaning all records are either encrypted or not.
|
meaning all records are either encrypted or not.
|
||||||
</summary>
|
</summary>
|
||||||
<param name="encryptionKey">A string value to use as the encryption key</param>
|
<param name="encryptionKey">A string value to use as the encryption key</param>
|
||||||
|
|
||||||
</member>
|
|
||||||
<member name="M:FileDbNs.FileDb.EncryptString(System.String,System.String)">
|
|
||||||
<summary>
|
|
||||||
Encrypt a string value.
|
|
||||||
Not syncronized.
|
|
||||||
</summary>
|
|
||||||
<param name="encryptKey">The key to use for encryption</param>
|
|
||||||
<param name="value">The value to encrypt</param>
|
|
||||||
<returns>The encrypted value as a string</returns>
|
|
||||||
|
|
||||||
</member>
|
|
||||||
<member name="M:FileDbNs.FileDb.DecryptString(System.String,System.String)">
|
|
||||||
<summary>
|
|
||||||
Decrypt a string value.
|
|
||||||
Not syncronized.
|
|
||||||
</summary>
|
|
||||||
<param name="encryptKey">The key to use for decryption</param>
|
|
||||||
<param name="value">The value to decrypt</param>
|
|
||||||
<returns>The decrypted value as a string</returns>
|
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FileDbNs.FileDb.SelectRecords``1(FileDbNs.FilterExpression)">
|
<member name="M:FileDbNs.FileDb.SelectRecords``1(FileDbNs.FilterExpression)">
|
||||||
<summary>
|
<summary>
|
||||||
|
|
@ -892,6 +899,39 @@
|
||||||
</summary>
|
</summary>
|
||||||
<param name="index">The record index</param>
|
<param name="index">The record index</param>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="T:FileDbNs.Encryptor">
|
||||||
|
<summary>
|
||||||
|
Class uses the .NET AesManaged class for data encryption, but ONLY on the Windows platform
|
||||||
|
build...the PCL build just returns the same data without doing anything. This is because
|
||||||
|
encryption namespace isn't available for PCLs. In this case, create your own Encryptor
|
||||||
|
class using the IEncryptor interface and set it into the FileDb object via SetEncryptor.
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.Encryptor.#ctor(System.String,System.String)">
|
||||||
|
<summary>
|
||||||
|
Constructor taking a key (password) and salt as a string
|
||||||
|
</summary>
|
||||||
|
<param name="encryptionKey"></param>
|
||||||
|
<param name="salt"></param>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.Encryptor.Encrypt(System.Byte[])">
|
||||||
|
<summary>
|
||||||
|
Encrypt the passed byte array
|
||||||
|
</summary>
|
||||||
|
<param name="dataToEncrypt">The data to encrypt</param>
|
||||||
|
<returns>The encrypted data</returns>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.Encryptor.Decrypt(System.Byte[])">
|
||||||
|
<summary>
|
||||||
|
Decrypt the passed byte array
|
||||||
|
</summary>
|
||||||
|
<param name="encryptedData">The data to decrypt</param>
|
||||||
|
<returns>The decrypted data</returns>
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
<member name="T:FileDbNs.DataTypeEnum_old">
|
<member name="T:FileDbNs.DataTypeEnum_old">
|
||||||
<summary>
|
<summary>
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -6,8 +6,10 @@
|
||||||
<members>
|
<members>
|
||||||
<member name="T:FileDbNs.FileDb">
|
<member name="T:FileDbNs.FileDb">
|
||||||
<summary>
|
<summary>
|
||||||
Represents an open FileDb database file. None of the FileDb classes are re-entrant -
|
Represents an open FileDb database file. All of the FileDb classes/methods are re-entrant -
|
||||||
access to the class objects must be syncronised by the calling application.
|
there is no need to syncronise access to the class objects by the calling application.
|
||||||
|
However you should use the try-finally pattern when you open a FileDb to ensure
|
||||||
|
prompt closing in the finally code block.
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
|
|
@ -471,34 +473,39 @@
|
||||||
<param name="fieldName">The name of the Field to rename</param>
|
<param name="fieldName">The name of the Field to rename</param>
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FileDbNs.FileDb.SetEncryptionKey(System.String)">
|
<member name="M:FileDbNs.FileDb.SetEncryptor(FileDbNs.IEncryptor)">
|
||||||
<summary>
|
<summary>
|
||||||
|
Used to set your own encryptor. Use this for cross-platform encryption scenarios, where you
|
||||||
|
have control over the encryption method being used. See the Windows Sample apps for an example.
|
||||||
|
</summary>
|
||||||
|
<param name="encryptor"></param>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.FileDb.EncryptString(System.String)">
|
||||||
|
<summary>
|
||||||
|
Convienience method to encrypt a string value. You must first call SetEncryptor with an Encryptor.
|
||||||
|
</summary>
|
||||||
|
<param name="value">The string to encrypt</param>
|
||||||
|
<returns>The encrypted value</returns>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.FileDb.DecryptString(System.String)">
|
||||||
|
<summary>
|
||||||
|
Decrypt a string value. You must first call SetEncryptor with an Encryptor.
|
||||||
|
</summary>
|
||||||
|
<param name="value">The string to decrypt</param>
|
||||||
|
<returns>The decrypted value</returns>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="M:FileDbNs.FileDb.SetEncryptionKey(System.String,System.String)">
|
||||||
|
<summary>
|
||||||
|
*** Only works on Windows platform. Use SetEncryptor to provide your own encryptor for cross platform databases ***
|
||||||
|
*** Do not use this method anymore ***
|
||||||
Allows you to set an encryption key after the database has been opened. You must set
|
Allows you to set an encryption key after the database has been opened. You must set
|
||||||
the encryption key before reading or writing to the database. Encryption is "all or nothing",
|
the encryption key before reading or writing to the database. Encryption is "all or nothing",
|
||||||
meaning all records are either encrypted or not.
|
meaning all records are either encrypted or not.
|
||||||
</summary>
|
</summary>
|
||||||
<param name="encryptionKey">A string value to use as the encryption key</param>
|
<param name="encryptionKey">A string value to use as the encryption key</param>
|
||||||
|
|
||||||
</member>
|
|
||||||
<member name="M:FileDbNs.FileDb.EncryptString(System.String,System.String)">
|
|
||||||
<summary>
|
|
||||||
Encrypt a string value.
|
|
||||||
Not syncronized.
|
|
||||||
</summary>
|
|
||||||
<param name="encryptKey">The key to use for encryption</param>
|
|
||||||
<param name="value">The value to encrypt</param>
|
|
||||||
<returns>The encrypted value as a string</returns>
|
|
||||||
|
|
||||||
</member>
|
|
||||||
<member name="M:FileDbNs.FileDb.DecryptString(System.String,System.String)">
|
|
||||||
<summary>
|
|
||||||
Decrypt a string value.
|
|
||||||
Not syncronized.
|
|
||||||
</summary>
|
|
||||||
<param name="encryptKey">The key to use for decryption</param>
|
|
||||||
<param name="value">The value to decrypt</param>
|
|
||||||
<returns>The decrypted value as a string</returns>
|
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:FileDbNs.FileDb.SelectRecords``1(FileDbNs.FilterExpression)">
|
<member name="M:FileDbNs.FileDb.SelectRecords``1(FileDbNs.FilterExpression)">
|
||||||
<summary>
|
<summary>
|
||||||
|
|
@ -860,6 +867,15 @@
|
||||||
</summary>
|
</summary>
|
||||||
<param name="index">The record index</param>
|
<param name="index">The record index</param>
|
||||||
|
|
||||||
|
</member>
|
||||||
|
<member name="T:FileDbNs.Encryptor">
|
||||||
|
<summary>
|
||||||
|
Class uses the .NET AesManaged class for data encryption, but ONLY on the Windows platform
|
||||||
|
build...the PCL build just returns the same data without doing anything. This is because
|
||||||
|
encryption namespace isn't available for PCLs. In this case, create your own Encryptor
|
||||||
|
class using the IEncryptor interface and set it into the FileDb object via SetEncryptor.
|
||||||
|
</summary>
|
||||||
|
|
||||||
</member>
|
</member>
|
||||||
<member name="T:FileDbNs.DataTypeEnum_old">
|
<member name="T:FileDbNs.DataTypeEnum_old">
|
||||||
<summary>
|
<summary>
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,9 @@
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\FileDb\FileDb.dll</HintPath>
|
<HintPath>..\FileDb\FileDb.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="PresentationCore" />
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Runtime.Caching" />
|
<Reference Include="System.Runtime.Caching" />
|
||||||
<Reference Include="System.Xaml" />
|
|
||||||
<Reference Include="WindowsBase" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="FileDbCache.cs" />
|
<Compile Include="FileDbCache.cs" />
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Caching;
|
using System.Runtime.Caching;
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using FileDbNs;
|
using FileDbNs;
|
||||||
|
|
||||||
namespace MapControl.Caching
|
namespace MapControl.Caching
|
||||||
|
|
@ -17,7 +16,6 @@ namespace MapControl.Caching
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ObjectCache implementation based on FileDb, a free and simple No-SQL database by EzTools Software.
|
/// ObjectCache implementation based on FileDb, a free and simple No-SQL database by EzTools Software.
|
||||||
/// See http://www.eztools-software.com/tools/filedb/.
|
/// See http://www.eztools-software.com/tools/filedb/.
|
||||||
/// The only valid data type for cached values is System.Windows.Media.Imaging.BitmapFrame.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FileDbCache : ObjectCache, IDisposable
|
public class FileDbCache : ObjectCache, IDisposable
|
||||||
{
|
{
|
||||||
|
|
@ -196,40 +194,19 @@ namespace MapControl.Caching
|
||||||
|
|
||||||
if (fileDb.IsOpen)
|
if (fileDb.IsOpen)
|
||||||
{
|
{
|
||||||
Record record = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
record = fileDb.GetRecordByKey(key, new string[] { valueField }, false);
|
var record = fileDb.GetRecordByKey(key, new string[] { valueField }, false);
|
||||||
|
|
||||||
|
if (record != null)
|
||||||
|
{
|
||||||
|
return record[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("FileDbCache: FileDb.GetRecordByKey(\"{0}\") failed: {1}", key, ex.Message);
|
Debug.WriteLine("FileDbCache: FileDb.GetRecordByKey(\"{0}\") failed: {1}", key, ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var memoryStream = new MemoryStream((byte[])record[0]))
|
|
||||||
{
|
|
||||||
return BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine("FileDbCache: Decoding \"{0}\" failed: {1}", key, ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fileDb.DeleteRecordByKey(key);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine("FileDbCache: FileDb.DeleteRecordByKey(\"{0}\") failed: {1}", key, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -254,6 +231,11 @@ namespace MapControl.Caching
|
||||||
throw new ArgumentNullException("The parameter key must not be null.");
|
throw new ArgumentNullException("The parameter key must not be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("The parameter value must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
if (policy == null)
|
if (policy == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("The parameter policy must not be null.");
|
throw new ArgumentNullException("The parameter policy must not be null.");
|
||||||
|
|
@ -264,50 +246,22 @@ namespace MapControl.Caching
|
||||||
throw new NotSupportedException("The parameter regionName must be null.");
|
throw new NotSupportedException("The parameter regionName must be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var bitmap = value as BitmapFrame;
|
|
||||||
|
|
||||||
if (bitmap == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("The parameter value must contain a System.Windows.Media.Imaging.BitmapFrame.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileDb.IsOpen)
|
if (fileDb.IsOpen)
|
||||||
{
|
{
|
||||||
byte[] buffer = null;
|
var expires = DateTime.MaxValue;
|
||||||
|
|
||||||
try
|
if (policy.AbsoluteExpiration != InfiniteAbsoluteExpiration)
|
||||||
{
|
{
|
||||||
var encoder = new PngBitmapEncoder();
|
expires = policy.AbsoluteExpiration.DateTime;
|
||||||
encoder.Frames.Add(bitmap);
|
|
||||||
|
|
||||||
using (var memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
encoder.Save(memoryStream);
|
|
||||||
buffer = memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
else if (policy.SlidingExpiration != NoSlidingExpiration)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("FileDbCache: Encoding \"{0}\" failed: {1}", key, ex.Message);
|
expires = DateTime.UtcNow + policy.SlidingExpiration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer != null)
|
if (!AddOrUpdateRecord(key, value, expires) && RepairDatabase())
|
||||||
{
|
{
|
||||||
var expires = DateTime.MaxValue;
|
AddOrUpdateRecord(key, value, expires);
|
||||||
|
|
||||||
if (policy.AbsoluteExpiration != InfiniteAbsoluteExpiration)
|
|
||||||
{
|
|
||||||
expires = policy.AbsoluteExpiration.DateTime;
|
|
||||||
}
|
|
||||||
else if (policy.SlidingExpiration != NoSlidingExpiration)
|
|
||||||
{
|
|
||||||
expires = DateTime.UtcNow + policy.SlidingExpiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AddOrUpdateRecord(key, buffer, expires) && RepairDatabase())
|
|
||||||
{
|
|
||||||
AddOrUpdateRecord(key, buffer, expires);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -447,7 +401,7 @@ namespace MapControl.Caching
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AddOrUpdateRecord(string key, byte[] value, DateTime expires)
|
private bool AddOrUpdateRecord(string key, object value, DateTime expires)
|
||||||
{
|
{
|
||||||
var fieldValues = new FieldValues(3);
|
var fieldValues = new FieldValues(3);
|
||||||
fieldValues.Add(valueField, value);
|
fieldValues.Add(valueField, value);
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,9 @@
|
||||||
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="PresentationCore" />
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Runtime.Caching" />
|
<Reference Include="System.Runtime.Caching" />
|
||||||
<Reference Include="System.Xaml" />
|
|
||||||
<Reference Include="WindowsBase" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ImageFileCache.cs" />
|
<Compile Include="ImageFileCache.cs" />
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,32 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Caching;
|
using System.Runtime.Caching;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
|
|
||||||
namespace MapControl.Caching
|
namespace MapControl.Caching
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ObjectCache implementation based on local image files.
|
/// ObjectCache implementation based on local image files.
|
||||||
/// The only valid data type for cached values is System.Windows.Media.Imaging.BitmapFrame.
|
/// The only valid data type for cached values is byte[].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ImageFileCache : ObjectCache
|
public class ImageFileCache : ObjectCache
|
||||||
{
|
{
|
||||||
|
private static readonly Tuple<string, byte[]>[] imageFileTypes = new Tuple<string, byte[]>[]
|
||||||
|
{
|
||||||
|
new Tuple<string, byte[]>(".png", new byte[] { 0x89, 0x50, 0x4E, 0x47, 0xD, 0xA, 0x1A, 0xA }),
|
||||||
|
new Tuple<string, byte[]>(".jpg", new byte[] { 0xFF, 0xD8, 0xFF, 0xE0, 0, 0x10, 0x4A, 0x46, 0x49, 0x46, 0 }),
|
||||||
|
new Tuple<string, byte[]>(".bmp", new byte[] { 0x42, 0x4D }),
|
||||||
|
new Tuple<string, byte[]>(".gif", new byte[] { 0x47, 0x49, 0x46 }),
|
||||||
|
new Tuple<string, byte[]>(".tif", new byte[] { 0x49, 0x49, 42, 0 }),
|
||||||
|
new Tuple<string, byte[]>(".tif", new byte[] { 0x4D, 0x4D, 0, 42 }),
|
||||||
|
new Tuple<string, byte[]>(".wdp", new byte[] { 0x49, 0x49, 0xBC }),
|
||||||
|
new Tuple<string, byte[]>(".bin", new byte[] { }),
|
||||||
|
};
|
||||||
|
|
||||||
private static readonly FileSystemAccessRule fullControlRule = new FileSystemAccessRule(
|
private static readonly FileSystemAccessRule fullControlRule = new FileSystemAccessRule(
|
||||||
new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
|
new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
|
||||||
FileSystemRights.FullControl, AccessControlType.Allow);
|
FileSystemRights.FullControl, AccessControlType.Allow);
|
||||||
|
|
@ -87,44 +97,52 @@ namespace MapControl.Caching
|
||||||
|
|
||||||
public override bool Contains(string key, string regionName = null)
|
public override bool Contains(string key, string regionName = null)
|
||||||
{
|
{
|
||||||
return memoryCache.Contains(key, regionName) || FindFile(GetPath(key)) != 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)
|
public override object Get(string key, string regionName = null)
|
||||||
{
|
{
|
||||||
var bitmap = memoryCache.Get(key, regionName) as BitmapFrame;
|
if (key == null)
|
||||||
|
|
||||||
if (bitmap == null)
|
|
||||||
{
|
{
|
||||||
try
|
throw new ArgumentNullException("The parameter key must not be null.");
|
||||||
{
|
}
|
||||||
var path = FindFile(GetPath(key));
|
|
||||||
|
|
||||||
if (path != 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
|
||||||
{
|
{
|
||||||
using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
buffer = File.ReadAllBytes(path);
|
||||||
{
|
memoryCache.Set(key, buffer, new CacheItemPolicy());
|
||||||
bitmap = BitmapFrame.Create(fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
}
|
||||||
|
catch (Exception ex)
|
||||||
var metadata = (BitmapMetadata)bitmap.Metadata;
|
{
|
||||||
DateTime expiration;
|
Debug.WriteLine("ImageFileCache: Writing file {0} failed: {1}", path, ex.Message);
|
||||||
|
|
||||||
// metadata.DateTaken must be parsed in CurrentCulture
|
|
||||||
if (metadata != null &&
|
|
||||||
metadata.DateTaken != null &&
|
|
||||||
DateTime.TryParse(metadata.DateTaken, CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out expiration))
|
|
||||||
{
|
|
||||||
memoryCache.Set(key, bitmap, expiration, regionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitmap;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override CacheItem GetCacheItem(string key, string regionName = null)
|
public override CacheItem GetCacheItem(string key, string regionName = null)
|
||||||
|
|
@ -141,59 +159,32 @@ namespace MapControl.Caching
|
||||||
|
|
||||||
public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
|
public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
|
||||||
{
|
{
|
||||||
var bitmap = value as BitmapFrame;
|
if (key == null)
|
||||||
|
|
||||||
if (bitmap == null)
|
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The parameter value must contain a System.Windows.Media.Imaging.BitmapFrame.");
|
throw new ArgumentNullException("The parameter key must not be null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadata = (BitmapMetadata)bitmap.Metadata;
|
if (regionName != null)
|
||||||
var format = metadata != null ? metadata.Format : "bmp";
|
|
||||||
BitmapEncoder encoder = null;
|
|
||||||
|
|
||||||
switch (format)
|
|
||||||
{
|
{
|
||||||
case "bmp":
|
throw new NotSupportedException("The parameter regionName must be null.");
|
||||||
encoder = new BmpBitmapEncoder();
|
|
||||||
break;
|
|
||||||
case "gif":
|
|
||||||
encoder = new GifBitmapEncoder();
|
|
||||||
break;
|
|
||||||
case "jpg":
|
|
||||||
encoder = new JpegBitmapEncoder();
|
|
||||||
break;
|
|
||||||
case "png":
|
|
||||||
encoder = new PngBitmapEncoder();
|
|
||||||
break;
|
|
||||||
case "tiff":
|
|
||||||
encoder = new TiffBitmapEncoder();
|
|
||||||
break;
|
|
||||||
case "wmphoto":
|
|
||||||
encoder = new WmpBitmapEncoder();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encoder == null)
|
var buffer = value as byte[];
|
||||||
|
|
||||||
|
if (buffer == null || buffer.Length == 0)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException(string.Format("The bitmap format {0} is not supported.", format));
|
throw new NotSupportedException("The parameter value must be a non-empty byte array.");
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryCache.Set(key, bitmap, policy, regionName);
|
memoryCache.Set(key, buffer, policy);
|
||||||
|
|
||||||
var path = string.Format("{0}.{1}", GetPath(key), format);
|
var path = Path.Combine(rootFolder, key)
|
||||||
|
+ imageFileTypes.First(t => t.Item2.SequenceEqual(buffer.Take(t.Item2.Length))).Item1;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
File.WriteAllBytes(path, buffer);
|
||||||
using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write))
|
|
||||||
{
|
|
||||||
encoder.Frames.Add(bitmap);
|
|
||||||
encoder.Save(fileStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileSecurity = File.GetAccessControl(path);
|
var fileSecurity = File.GetAccessControl(path);
|
||||||
fileSecurity.AddAccessRule(fullControlRule);
|
fileSecurity.AddAccessRule(fullControlRule);
|
||||||
|
|
@ -240,43 +231,56 @@ namespace MapControl.Caching
|
||||||
|
|
||||||
public override object Remove(string key, string regionName = null)
|
public override object Remove(string key, string regionName = null)
|
||||||
{
|
{
|
||||||
var oldValue = Get(key, regionName);
|
if (key == null)
|
||||||
|
|
||||||
memoryCache.Remove(key, regionName);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var path = FindFile(GetPath(key));
|
throw new ArgumentNullException("The parameter key must not be null.");
|
||||||
|
}
|
||||||
|
|
||||||
if (path != 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);
|
File.Delete(path);
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
catch
|
{
|
||||||
{
|
Debug.WriteLine("ImageFileCache: Removing file {0} failed: {1}", path, ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return oldValue;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetPath(string key)
|
private string FindFile(string key)
|
||||||
{
|
{
|
||||||
return Path.Combine(rootFolder, key);
|
var path = Path.Combine(rootFolder, key);
|
||||||
}
|
|
||||||
|
|
||||||
private static string FindFile(string path)
|
try
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(Path.GetExtension(path)))
|
|
||||||
{
|
{
|
||||||
return path;
|
if (!string.IsNullOrEmpty(Path.GetExtension(path)))
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
string folderName = Path.GetDirectoryName(path);
|
||||||
|
|
||||||
|
if (Directory.Exists(folderName))
|
||||||
|
{
|
||||||
|
return Directory.EnumerateFiles(folderName, Path.GetFileName(path) + ".*").FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
string folderName = Path.GetDirectoryName(path);
|
|
||||||
|
|
||||||
if (Directory.Exists(folderName))
|
|
||||||
{
|
{
|
||||||
return Directory.EnumerateFiles(folderName, Path.GetFileName(path) + ".*").FirstOrDefault();
|
Debug.WriteLine("ImageFileCache: Finding file {0} failed: {1}", path, ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -40,30 +40,26 @@ namespace MapControl.Caching
|
||||||
{
|
{
|
||||||
var item = await rootFolder.TryGetItemAsync(key);
|
var item = await rootFolder.TryGetItemAsync(key);
|
||||||
|
|
||||||
if (item == null || !item.IsOfType(StorageItemTypes.File))
|
if (item != null && item.IsOfType(StorageItemTypes.File))
|
||||||
{
|
{
|
||||||
return null;
|
var file = (StorageFile)item;
|
||||||
|
//Debug.WriteLine("ImageFileCache: Reading file {0}", file.Path);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new ImageCacheItem
|
||||||
|
{
|
||||||
|
Buffer = await FileIO.ReadBufferAsync(file),
|
||||||
|
Expires = (await file.Properties.GetImagePropertiesAsync()).DateTaken.UtcDateTime
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("ImageFileCache: Reading file {0} failed: {1}", file.Path, ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = (StorageFile)item;
|
return null;
|
||||||
|
|
||||||
var cacheItem = new ImageCacheItem
|
|
||||||
{
|
|
||||||
Buffer = await FileIO.ReadBufferAsync(file)
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Use ImageProperties.DateTaken to get expiration date
|
|
||||||
var imageProperties = await file.Properties.GetImagePropertiesAsync();
|
|
||||||
cacheItem.Expires = imageProperties.DateTaken.UtcDateTime;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//Debug.WriteLine("Loaded cached image {0}", file.Path);
|
|
||||||
return cacheItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task SetAsync(string key, IBuffer buffer, DateTime expires)
|
public virtual async Task SetAsync(string key, IBuffer buffer, DateTime expires)
|
||||||
|
|
@ -79,16 +75,18 @@ namespace MapControl.Caching
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = await folder.CreateFileAsync(names[names.Length - 1], CreationCollisionOption.ReplaceExisting);
|
var file = await folder.CreateFileAsync(names[names.Length - 1], CreationCollisionOption.ReplaceExisting);
|
||||||
|
//Debug.WriteLine("ImageFileCache: Writing file {0}", file.Path);
|
||||||
|
|
||||||
await FileIO.WriteBufferAsync(file, buffer);
|
await FileIO.WriteBufferAsync(file, buffer);
|
||||||
|
|
||||||
// Use ImageProperties.DateTaken to store expiration date
|
// Store expiration date in ImageProperties.DateTaken
|
||||||
var imageProperties = await file.Properties.GetImagePropertiesAsync();
|
var properties = await file.Properties.GetImagePropertiesAsync();
|
||||||
imageProperties.DateTaken = expires;
|
properties.DateTaken = expires;
|
||||||
await imageProperties.SavePropertiesAsync();
|
await properties.SavePropertiesAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.WriteLine(ex.Message);
|
Debug.WriteLine("ImageFileCache: Writing file {0}\\{1} failed: {2}", rootFolder.Path, key, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
namespace MapControl
|
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 class BingMapsTileLayer : TileLayer
|
||||||
{
|
{
|
||||||
public enum MapMode
|
public enum MapMode
|
||||||
|
|
@ -26,6 +29,12 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
public BingMapsTileLayer()
|
public BingMapsTileLayer()
|
||||||
|
: this(new TileImageLoader())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public BingMapsTileLayer(ITileImageLoader tileImageLoader)
|
||||||
|
: base(tileImageLoader)
|
||||||
{
|
{
|
||||||
MinZoomLevel = 1;
|
MinZoomLevel = 1;
|
||||||
MaxZoomLevel = 21;
|
MaxZoomLevel = 21;
|
||||||
|
|
@ -43,7 +52,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ApiKey))
|
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);
|
var uri = string.Format("http://dev.virtualearth.net/REST/V1/Imagery/Metadata/{0}?output=xml&key={1}", Mode, ApiKey);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
internal class BingMapsTileSource : TileSource
|
internal class BingMapsTileSource : TileSource
|
||||||
{
|
{
|
||||||
private string[] subdomains;
|
private readonly string[] subdomains;
|
||||||
|
|
||||||
public BingMapsTileSource(string uriFormat, string[] subdomains)
|
public BingMapsTileSource(string uriFormat, string[] subdomains)
|
||||||
: base(uriFormat)
|
: base(uriFormat)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Windows.Input;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default input event handling.
|
/// MapBase with default input event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Map : MapBase
|
public class Map : MapBase
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Windows.Input;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default input event handling.
|
/// MapBase with default input event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Map : MapBase
|
public class Map : MapBase
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ using Windows.UI.Xaml.Input;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default input event handling.
|
/// MapBase with default input event handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Map : MapBase
|
public class Map : MapBase
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ using System.Windows.Media.Animation;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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 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.
|
/// 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.
|
/// MapBase can contain map overlay child elements like other MapPanels or MapItemsControls.
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ using System.Windows;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Runtime.Caching;
|
using System.Runtime.Caching;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
@ -197,7 +198,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Loading tile image failed: {0}", (object)ex.Message);
|
Debug.WriteLine("ImageTileSource.LoadImage: " + ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
|
@ -218,7 +219,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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
|
try
|
||||||
{
|
{
|
||||||
var request = HttpWebRequest.CreateHttp(uri);
|
var request = HttpWebRequest.CreateHttp(uri);
|
||||||
request.UserAgent = HttpUserAgent;
|
|
||||||
|
if (HttpUserAgent != null)
|
||||||
|
{
|
||||||
|
request.UserAgent = HttpUserAgent;
|
||||||
|
}
|
||||||
|
|
||||||
using (var response = (HttpWebResponse)request.GetResponse())
|
using (var response = (HttpWebResponse)request.GetResponse())
|
||||||
{
|
{
|
||||||
|
|
@ -240,23 +245,24 @@ namespace MapControl
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
responseStream.CopyTo(memoryStream);
|
responseStream.CopyTo(memoryStream);
|
||||||
memoryStream.Position = 0;
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
image = BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cacheKey != null)
|
image = BitmapFrame.Create(memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||||
{
|
|
||||||
SetCachedImage(cacheKey, image, GetExpiration(response.Headers));
|
if (cacheKey != null)
|
||||||
|
{
|
||||||
|
SetCachedImage(cacheKey, memoryStream, GetExpiration(response.Headers));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (WebException ex)
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Downloading {0} failed: {1}", uri, ex.Message);
|
Debug.WriteLine("{0}: {1}", uri, ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
|
|
@ -274,34 +280,44 @@ namespace MapControl
|
||||||
|
|
||||||
private static bool GetCachedImage(string cacheKey, out BitmapSource image)
|
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;
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
memoryStream.Seek(0, SeekOrigin.End);
|
||||||
var metadata = (BitmapMetadata)bitmap.Metadata;
|
memoryStream.Write(Encoding.ASCII.GetBytes("EXPIRES:"), 0, 8);
|
||||||
|
memoryStream.Write(BitConverter.GetBytes(expiration.Ticks), 0, 8);
|
||||||
|
|
||||||
// store cache expiration date in BitmapMetadata.DateTaken
|
Cache.Set(cacheKey, memoryStream.ToArray(), new CacheItemPolicy { AbsoluteExpiration = expiration });
|
||||||
metadata.DateTaken = expiration.ToString(CultureInfo.InvariantCulture);
|
|
||||||
metadata.Freeze();
|
|
||||||
bitmap.Freeze();
|
|
||||||
|
|
||||||
Cache.Set(cacheKey, bitmap, new CacheItemPolicy { AbsoluteExpiration = expiration });
|
|
||||||
|
|
||||||
//Debug.WriteLine("Cached {0}, Expires {1}", cacheKey, expiration);
|
//Debug.WriteLine("Cached {0}, Expires {1}", cacheKey, expiration);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ using System.Windows.Threading;
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills a rectangular area with map tiles from a TileSource.
|
/// Fills the map viewport with map tiles from a TileSource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if NETFX_CORE
|
#if NETFX_CORE
|
||||||
[ContentProperty(Name = "TileSource")]
|
[ContentProperty(Name = "TileSource")]
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ namespace MapControl
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Uri(uriFormat
|
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)),
|
.Replace("{q}", new string(quadkey)),
|
||||||
UriKind.RelativeOrAbsolute);
|
UriKind.RelativeOrAbsolute);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ namespace UniversalApp
|
||||||
public MainPage()
|
public MainPage()
|
||||||
{
|
{
|
||||||
//TileImageLoader.Cache = new MapControl.Caching.ImageFileCache();
|
//TileImageLoader.Cache = new MapControl.Caching.ImageFileCache();
|
||||||
|
//TileImageLoader.Cache = new MapControl.Caching.FileDbCache();
|
||||||
|
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,10 @@
|
||||||
</Page>
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Caching\FileDbCache.WinRT\FileDbCache.WinRT.csproj">
|
||||||
|
<Project>{c7bf2b18-cc74-430b-bcb2-600304efa3d8}</Project>
|
||||||
|
<Name>FileDbCache.WinRT</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\Caching\ImageFileCache.WinRT\ImageFileCache.WinRT.csproj">
|
<ProjectReference Include="..\..\Caching\ImageFileCache.WinRT\ImageFileCache.WinRT.csproj">
|
||||||
<Project>{f789647e-96f7-43e3-a895-fa3fe8d01260}</Project>
|
<Project>{f789647e-96f7-43e3-a895-fa3fe8d01260}</Project>
|
||||||
<Name>ImageFileCache.WinRT</Name>
|
<Name>ImageFileCache.WinRT</Name>
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyCompany("Clemens Fischer")]
|
[assembly: AssemblyCompany("Clemens Fischer")]
|
||||||
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
[assembly: AssemblyCopyright("© 2015 Clemens Fischer")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyVersion("2.6.0")]
|
[assembly: AssemblyVersion("2.7.0")]
|
||||||
[assembly: AssemblyFileVersion("2.6.0")]
|
[assembly: AssemblyFileVersion("2.7.0")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue