Version 4: Upgrade to VS 2017

This commit is contained in:
ClemensF 2017-08-04 21:38:58 +02:00
parent 2aafe32e00
commit ec47f225b3
142 changed files with 1828 additions and 18384 deletions

View file

@ -1,37 +1,69 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}</ProjectGuid> <ProjectGuid>{3FF37D40-F770-45B2-95DD-7A84093E1425}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl.Caching</RootNamespace> <RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyName>FileDbCache.WinRT</AssemblyName> <AssemblyName>FileDbCache.UWP</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage> <DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile32</TargetFrameworkProfile> <RuntimeIdentifiers>win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot</RuntimeIdentifiers>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType> <DebugType>none</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<None Include="..\..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileDbCache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\FileDbCache.UWP.rd.xml" />
</ItemGroup>
<ItemGroup>
<Reference Include="FileDbPcl">
<HintPath>..\FileDb\FileDbPcl.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\UWP\MapControl.UWP.csproj">
<Project>{951bc5d2-d653-42d9-9a91-21dc50de0182}</Project>
<Name>MapControl.UWP</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
@ -39,31 +71,7 @@
<PropertyGroup> <PropertyGroup>
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<TargetPlatform Include="WindowsPhoneApp, Version=8.1" />
<TargetPlatform Include="Windows, Version=8.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileDbCache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\WinRT\MapControl.WinRT.csproj">
<Project>{63cefdf7-5170-43b6-86f8-5c4a383a1615}</Project>
<Name>MapControl.WinRT</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="FileDbPcl">
<HintPath>..\FileDb\FileDbPcl.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild"> <Target Name="BeforeBuild">

View file

@ -18,35 +18,33 @@ namespace MapControl.Caching
/// IImageCache implementation based on FileDb, a free and simple No-SQL database by EzTools Software. /// IImageCache 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/.
/// </summary> /// </summary>
public class FileDbCache : IImageCache, IDisposable public sealed class FileDbCache : IImageCache, IDisposable
{ {
private const string keyField = "Key"; private const string keyField = "Key";
private const string valueField = "Value"; private const string valueField = "Value";
private const string expiresField = "Expires"; private const string expiresField = "Expires";
private readonly FileDb fileDb = new FileDb { AutoFlush = true, AutoCleanThreshold = -1 }; private readonly FileDb fileDb = new FileDb();
private readonly StorageFolder folder; private readonly StorageFolder folder;
private readonly string name; private readonly string fileName;
public FileDbCache(string name = null, StorageFolder folder = null) public FileDbCache(StorageFolder folder, string fileName = "TileCache.fdb", bool autoFlush = true, int autoCleanThreshold = -1)
{ {
if (string.IsNullOrEmpty(name))
{
name = TileImageLoader.DefaultCacheName;
}
if (string.IsNullOrEmpty(Path.GetExtension(name)))
{
name += ".fdb";
}
if (folder == null) if (folder == null)
{ {
folder = TileImageLoader.DefaultCacheFolder; throw new ArgumentNullException("The parameter folder must not be null.");
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("The parameter fileName must not be null.");
} }
this.folder = folder; this.folder = folder;
this.name = name; this.fileName = fileName;
fileDb.AutoFlush = autoFlush;
fileDb.AutoCleanThreshold = autoCleanThreshold;
Application.Current.Resuming += async (s, e) => await Open(); Application.Current.Resuming += async (s, e) => await Open();
Application.Current.Suspending += (s, e) => Close(); Application.Current.Suspending += (s, e) => Close();
@ -73,7 +71,7 @@ namespace MapControl.Caching
} }
} }
public async Task<ImageCacheItem> GetAsync(string key) public Task<ImageCacheItem> GetAsync(string key)
{ {
if (key == null) if (key == null)
{ {
@ -85,10 +83,10 @@ namespace MapControl.Caching
return null; return null;
} }
return await Task.Run(() => Get(key)); return Task.Run(() => Get(key));
} }
public async Task SetAsync(string key, IBuffer buffer, DateTime expiration) public Task SetAsync(string key, IBuffer buffer, DateTime expiration)
{ {
if (key == null) if (key == null)
{ {
@ -100,16 +98,19 @@ namespace MapControl.Caching
throw new ArgumentNullException("The parameter buffer must not be null."); throw new ArgumentNullException("The parameter buffer must not be null.");
} }
return Task.Run(async () =>
{
if (fileDb.IsOpen) if (fileDb.IsOpen)
{ {
var bytes = buffer.ToArray(); var bytes = buffer.ToArray();
var ok = await Task.Run(() => AddOrUpdateRecord(key, bytes, expiration)); var ok = AddOrUpdateRecord(key, bytes, expiration);
if (!ok && (await RepairDatabase())) if (!ok && (await RepairDatabase()))
{ {
await Task.Run(() => AddOrUpdateRecord(key, bytes, expiration)); AddOrUpdateRecord(key, bytes, expiration);
} }
} }
});
} }
private async Task Open() private async Task Open()
@ -118,22 +119,20 @@ namespace MapControl.Caching
{ {
try try
{ {
var file = await folder.GetFileAsync(name); var file = await folder.GetFileAsync(fileName);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite); var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
fileDb.Open(stream.AsStream()); fileDb.Open(stream.AsStream());
Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, file.Path); Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, file.Path);
Clean(); Clean();
return;
} }
catch catch
{ {
}
await CreateDatabase(); await CreateDatabase();
} }
} }
}
private void Close() private void Close()
{ {
@ -147,7 +146,7 @@ namespace MapControl.Caching
{ {
Close(); Close();
var file = await folder.CreateFileAsync(name, CreationCollisionOption.ReplaceExisting); var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
var stream = await file.OpenAsync(FileAccessMode.ReadWrite); var stream = await file.OpenAsync(FileAccessMode.ReadWrite);
fileDb.Create(stream.AsStream(), new Field[] fileDb.Create(stream.AsStream(), new Field[]
@ -179,7 +178,7 @@ namespace MapControl.Caching
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.WriteLine("FileDbCache: Creating database {0}: {1}", Path.Combine(folder.Path, name), ex.Message); Debug.WriteLine("FileDbCache: Creating database {0}: {1}", Path.Combine(folder.Path, fileName), ex.Message);
} }
return false; return false;

View file

@ -1,14 +1,14 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
[assembly: AssemblyTitle("XAML Map Control FileDbCache (WinRT)")] [assembly: AssemblyTitle("XAML Map Control FileDbCache for UWP")]
[assembly: AssemblyDescription("IImageCache implementation based on EzTools FileDb")] [assembly: AssemblyDescription("IImageCache implementation based on EzTools FileDb")]
[assembly: AssemblyProduct("XAML Map Control")] [assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.4.1")] [assembly: AssemblyVersion("4.0.0")]
[assembly: AssemblyFileVersion("3.4.1")] [assembly: AssemblyFileVersion("4.0.0")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="FileDbCache.UWP">
</Library>
</Directives>

View file

@ -0,0 +1,16 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

View file

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <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> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion> <ProjectGuid>{AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{EF44F661-B98A-4676-927F-85D138F82300}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl.Caching</RootNamespace> <RootNamespace>MapControl.Caching</RootNamespace>
@ -18,20 +17,18 @@
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
@ -40,12 +37,10 @@
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="FileDb, Version=5.0.1.0, Culture=neutral, PublicKeyToken=ba3f58a0e60cd01d, processorArchitecture=MSIL"> <Reference Include="FileDb">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\FileDb\FileDb.dll</HintPath> <HintPath>..\FileDb\FileDb.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Caching" /> <Reference Include="System.Runtime.Caching" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -57,7 +52,6 @@
<Link>MapControl.snk</Link> <Link>MapControl.snk</Link>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -2,14 +2,13 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using FileDbNs;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Caching; using System.Runtime.Caching;
using FileDbNs;
namespace MapControl.Caching namespace MapControl.Caching
{ {
@ -17,71 +16,37 @@ namespace MapControl.Caching
/// 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/.
/// </summary> /// </summary>
public class FileDbCache : ObjectCache, IDisposable public sealed class FileDbCache : ObjectCache, IDisposable
{ {
private const string keyField = "Key"; private const string keyField = "Key";
private const string valueField = "Value"; private const string valueField = "Value";
private const string expiresField = "Expires"; private const string expiresField = "Expires";
private readonly FileDb fileDb = new FileDb { AutoFlush = true, AutoCleanThreshold = -1 }; private readonly FileDb fileDb = new FileDb();
private readonly string name; private readonly string dbPath;
private readonly string path;
public FileDbCache(string name, NameValueCollection config) public FileDbCache(string path, bool autoFlush = true, int autoCleanThreshold = -1)
: this(name, config["folder"])
{ {
var autoFlush = config["autoFlush"]; if (string.IsNullOrEmpty(path))
var autoCleanThreshold = config["autoCleanThreshold"];
if (autoFlush != null)
{ {
try throw new ArgumentException("The parameter path must not be null or empty.");
{
fileDb.AutoFlush = bool.Parse(autoFlush);
} }
catch (Exception ex)
{
throw new ArgumentException("The configuration parameter autoFlush must be a boolean value.", ex);
}
}
if (autoCleanThreshold != null)
{
try
{
fileDb.AutoCleanThreshold = int.Parse(autoCleanThreshold);
}
catch (Exception ex)
{
throw new ArgumentException("The configuration parameter autoCleanThreshold must be an integer value.", ex);
}
}
}
public FileDbCache(string name, string folder)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("The parameter name must not be null or empty.");
}
if (string.IsNullOrEmpty(folder))
{
throw new ArgumentException("The parameter folder must not be null or empty.");
}
this.name = name;
path = Path.Combine(folder, name);
if (string.IsNullOrEmpty(Path.GetExtension(path))) if (string.IsNullOrEmpty(Path.GetExtension(path)))
{ {
path += ".fdb"; path = Path.Combine(path, "TileCache.fdb");
} }
dbPath = path;
fileDb.AutoFlush = autoFlush;
fileDb.AutoCleanThreshold = autoCleanThreshold;
try try
{ {
fileDb.Open(path, false); fileDb.Open(dbPath, false);
Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, path);
Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, dbPath);
Clean(); Clean();
} }
@ -93,21 +58,9 @@ namespace MapControl.Caching
AppDomain.CurrentDomain.ProcessExit += (s, e) => Close(); AppDomain.CurrentDomain.ProcessExit += (s, e) => Close();
} }
public bool AutoFlush
{
get { return fileDb.AutoFlush; }
set { fileDb.AutoFlush = value; }
}
public int AutoCleanThreshold
{
get { return fileDb.AutoCleanThreshold; }
set { fileDb.AutoCleanThreshold = value; }
}
public override string Name public override string Name
{ {
get { return name; } get { return string.Empty; }
} }
public override DefaultCacheCapabilities DefaultCacheCapabilities public override DefaultCacheCapabilities DefaultCacheCapabilities
@ -357,23 +310,23 @@ namespace MapControl.Caching
{ {
Close(); Close();
if (File.Exists(path)) if (File.Exists(dbPath))
{ {
File.Delete(path); File.Delete(dbPath);
} }
else else
{ {
Directory.CreateDirectory(Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(dbPath));
} }
fileDb.Create(path, new Field[] fileDb.Create(dbPath, new Field[]
{ {
new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true }, new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true },
new Field(valueField, DataTypeEnum.Byte) { IsArray = true }, new Field(valueField, DataTypeEnum.Byte) { IsArray = true },
new Field(expiresField, DataTypeEnum.DateTime) new Field(expiresField, DataTypeEnum.DateTime)
}); });
Debug.WriteLine("FileDbCache: Created database " + path); Debug.WriteLine("FileDbCache: Created database " + dbPath);
} }
private bool RepairDatabase() private bool RepairDatabase()
@ -395,7 +348,7 @@ namespace MapControl.Caching
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.WriteLine("FileDbCache: Failed creating database {0}: {1}", path, ex.Message); Debug.WriteLine("FileDbCache: Failed creating database {0}: {1}", dbPath, ex.Message);
} }
return false; return false;

View file

@ -1,14 +1,14 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
[assembly: AssemblyTitle("XAML Map Control FileDbCache (WPF)")] [assembly: AssemblyTitle("XAML Map Control FileDbCache for WPF")]
[assembly: AssemblyDescription("ObjectCache implementation based on EzTools FileDb")] [assembly: AssemblyDescription("ObjectCache implementation based on EzTools FileDb")]
[assembly: AssemblyProduct("XAML Map Control")] [assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.4.1")] [assembly: AssemblyVersion("4.0.0")]
[assembly: AssemblyFileVersion("3.4.1")] [assembly: AssemblyFileVersion("4.0.0")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{86470440-FEE2-4120-AF5A-3762FB9C536F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyName>ImageFileCache.WPF</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<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>
<Prefer32Bit>false</Prefer32Bit>
</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>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Caching" />
</ItemGroup>
<ItemGroup>
<Compile Include="ImageFileCache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
</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>

View file

@ -1,14 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("XAML Map Control ImageFileCache (WPF)")]
[assembly: AssemblyDescription("ObjectCache implementation based on local image files")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.4.1")]
[assembly: AssemblyFileVersion("3.4.1")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.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>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F789647E-96F7-43E3-A895-FA3FE8D01260}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyName>ImageFileCache.WinRT</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
<TargetPlatformVersion>8.1</TargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_APP</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;NETFX_CORE;WINDOWS_APP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="..\..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
</ItemGroup>
<ItemGroup>
<Compile Include="ImageFileCache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\MapControl\WinRT\MapControl.WinRT.csproj">
<Project>{63cefdf7-5170-43b6-86f8-5c4a383a1615}</Project>
<Name>MapControl.WinRT</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.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>

View file

@ -1,93 +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;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
namespace MapControl.Caching
{
public class ImageFileCache : IImageCache
{
private readonly string name;
private StorageFolder rootFolder;
public ImageFileCache(string name = null, StorageFolder folder = null)
{
if (string.IsNullOrEmpty(name))
{
name = TileImageLoader.DefaultCacheName;
}
if (folder == null)
{
folder = TileImageLoader.DefaultCacheFolder;
}
this.name = name;
folder.CreateFolderAsync(name, CreationCollisionOption.OpenIfExists).Completed = (o, s) =>
{
rootFolder = o.GetResults();
Debug.WriteLine("Created ImageFileCache in " + rootFolder.Path);
};
}
public virtual async Task<ImageCacheItem> GetAsync(string key)
{
var item = await rootFolder.TryGetItemAsync(key);
if (item != null && item.IsOfType(StorageItemTypes.File))
{
var file = (StorageFile)item;
//Debug.WriteLine("ImageFileCache: Reading " + file.Path);
try
{
return new ImageCacheItem
{
Buffer = await FileIO.ReadBufferAsync(file),
Expiration = (await file.Properties.GetImagePropertiesAsync()).DateTaken.UtcDateTime
};
}
catch (Exception ex)
{
Debug.WriteLine("ImageFileCache: Reading {0}: {1}", file.Path, ex.Message);
}
}
return null;
}
public virtual async Task SetAsync(string key, IBuffer buffer, DateTime expiration)
{
try
{
var names = key.Split('\\');
var folder = rootFolder;
for (int i = 0; i < names.Length - 1; i++)
{
folder = await folder.CreateFolderAsync(names[i], CreationCollisionOption.OpenIfExists);
}
var file = await folder.CreateFileAsync(names[names.Length - 1], CreationCollisionOption.ReplaceExisting);
//Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", file.Path, expiration.ToLocalTime());
await FileIO.WriteBufferAsync(file, buffer);
// Store expiration date in ImageProperties.DateTaken
var properties = await file.Properties.GetImagePropertiesAsync();
properties.DateTaken = expiration;
await properties.SavePropertiesAsync();
}
catch (Exception ex)
{
Debug.WriteLine("ImageFileCache: Writing {0}\\{1}: {2}", rootFolder.Path, key, ex.Message);
}
}
}
}

View file

@ -1,14 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("XAML Map Control ImageFileCache (WinRT)")]
[assembly: AssemblyDescription("IImageCache implementation based on local image files")]
[assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.4.1")]
[assembly: AssemblyFileVersion("3.4.1")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -1,33 +1,25 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.25420.1 VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WinRT", "Caching\FileDbCache.WinRT\FileDbCache.WinRT.csproj", "{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MapControl", "MapControl", "{52AECE49-F314-4F76-98F2-FA800F07824B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WPF", "Caching\FileDbCache.WPF\FileDbCache.WPF.csproj", "{EF44F661-B98A-4676-927F-85D138F82300}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WPF", "MapControl\WPF\MapControl.WPF.csproj", "{A204A102-C745-4D65-AEC8-7B96FAEDEF2D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageFileCache.WinRT", "Caching\ImageFileCache.WinRT\ImageFileCache.WinRT.csproj", "{F789647E-96F7-43E3-A895-FA3FE8D01260}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.UWP", "MapControl\UWP\MapControl.UWP.csproj", "{951BC5D2-D653-42D9-9A91-21DC50DE0182}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageFileCache.WPF", "Caching\ImageFileCache.WPF\ImageFileCache.WPF.csproj", "{86470440-FEE2-4120-AF5A-3762FB9C536F}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching", "Caching", "{6A596588-F93F-47CC-BE5D-58C3B34ADDEB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.Silverlight", "MapControl\MapControl.Silverlight.csproj", "{EB133B78-DEFF-416A-8F0C-89E54D766576}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{8F2103C2-78AF-4810-8FB9-67572F50C8FC}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WinRT", "MapControl\WinRT\MapControl.WinRT.csproj", "{63CEFDF7-5170-43B6-86F8-5C4A383A1615}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{F92DA93D-75DB-4308-A5F9-6B4C3908A675}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WPF", "MapControl\MapControl.WPF.csproj", "{226F3575-B683-446D-A2F0-181291DC8787}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApps\WpfApplication\WpfApplication.csproj", "{9949326E-9261-4F95-89B1-151F60498951}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleApps", "SampleApps", "{100879CC-8910-459E-856E-253D629E45DE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caching", "Caching", "{AE8A7E02-0F7D-41B0-AB23-15394150ED17}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalApp", "SampleApps\UniversalApp\UniversalApp.csproj", "{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication", "SampleApps\SilverlightApplication\SilverlightApplication.csproj", "{85AACDB7-959D-406D-A8DF-2F1E013F8F40}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.WPF", "Caching\FileDbCache.WPF\FileDbCache.WPF.csproj", "{AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication.Web", "SampleApps\SilverlightApplication.Web\SilverlightApplication.Web.csproj", "{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.UWP", "Caching\FileDbCache.UWP\FileDbCache.UWP.csproj", "{3FF37D40-F770-45B2-95DD-7A84093E1425}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -41,135 +33,57 @@ Global
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|ARM.ActiveCfg = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|ARM.ActiveCfg = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|ARM.Build.0 = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|ARM.Build.0 = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x64.ActiveCfg = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|x64.ActiveCfg = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x64.Build.0 = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|x64.Build.0 = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x86.ActiveCfg = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|x86.ActiveCfg = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Debug|x86.Build.0 = Debug|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Debug|x86.Build.0 = Debug|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|Any CPU.Build.0 = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|Any CPU.Build.0 = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|ARM.ActiveCfg = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|ARM.ActiveCfg = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|ARM.Build.0 = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|ARM.Build.0 = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x64.ActiveCfg = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|x64.ActiveCfg = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x64.Build.0 = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|x64.Build.0 = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x86.ActiveCfg = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|x86.ActiveCfg = Release|Any CPU
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8}.Release|x86.Build.0 = Release|Any CPU {A204A102-C745-4D65-AEC8-7B96FAEDEF2D}.Release|x86.Build.0 = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|Any CPU.Build.0 = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|ARM.ActiveCfg = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|ARM.ActiveCfg = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|ARM.Build.0 = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|ARM.Build.0 = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|x64.ActiveCfg = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|x64.ActiveCfg = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|x64.Build.0 = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|x64.Build.0 = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|x86.ActiveCfg = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|x86.ActiveCfg = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Debug|x86.Build.0 = Debug|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Debug|x86.Build.0 = Debug|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.ActiveCfg = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|Any CPU.Build.0 = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|Any CPU.Build.0 = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|ARM.ActiveCfg = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|ARM.ActiveCfg = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|ARM.Build.0 = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|ARM.Build.0 = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|x64.ActiveCfg = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|x64.ActiveCfg = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|x64.Build.0 = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|x64.Build.0 = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|x86.ActiveCfg = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|x86.ActiveCfg = Release|Any CPU
{EF44F661-B98A-4676-927F-85D138F82300}.Release|x86.Build.0 = Release|Any CPU {951BC5D2-D653-42D9-9A91-21DC50DE0182}.Release|x86.Build.0 = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|Any CPU.Build.0 = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|ARM.ActiveCfg = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|ARM.ActiveCfg = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|ARM.Build.0 = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|ARM.Build.0 = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x64.ActiveCfg = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x64.ActiveCfg = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x64.Build.0 = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x64.Build.0 = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x86.ActiveCfg = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x86.ActiveCfg = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Debug|x86.Build.0 = Debug|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Debug|x86.Build.0 = Debug|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.ActiveCfg = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|Any CPU.Build.0 = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|Any CPU.Build.0 = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|ARM.ActiveCfg = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|ARM.ActiveCfg = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|ARM.Build.0 = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|ARM.Build.0 = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x64.ActiveCfg = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x64.ActiveCfg = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x64.Build.0 = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x64.Build.0 = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x86.ActiveCfg = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x86.ActiveCfg = Release|Any CPU
{F789647E-96F7-43E3-A895-FA3FE8D01260}.Release|x86.Build.0 = Release|Any CPU {F92DA93D-75DB-4308-A5F9-6B4C3908A675}.Release|x86.Build.0 = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|x64
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Build.0 = Debug|x64
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|ARM.ActiveCfg = Debug|Any CPU {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.Deploy.0 = Debug|x64
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|ARM.Build.0 = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x64.ActiveCfg = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x64.Build.0 = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x86.ActiveCfg = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Debug|x86.Build.0 = Debug|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|Any CPU.Build.0 = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|ARM.ActiveCfg = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|ARM.Build.0 = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x64.ActiveCfg = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x64.Build.0 = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x86.ActiveCfg = Release|Any CPU
{86470440-FEE2-4120-AF5A-3762FB9C536F}.Release|x86.Build.0 = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|ARM.ActiveCfg = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|ARM.Build.0 = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x64.ActiveCfg = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x64.Build.0 = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x86.ActiveCfg = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Debug|x86.Build.0 = Debug|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.Build.0 = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|ARM.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|ARM.Build.0 = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x64.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x64.Build.0 = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x86.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|x86.Build.0 = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|ARM.ActiveCfg = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|ARM.Build.0 = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x64.ActiveCfg = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x64.Build.0 = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x86.ActiveCfg = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Debug|x86.Build.0 = Debug|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|Any CPU.Build.0 = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|ARM.ActiveCfg = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|ARM.Build.0 = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x64.ActiveCfg = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x64.Build.0 = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x86.ActiveCfg = Release|Any CPU
{63CEFDF7-5170-43B6-86F8-5C4A383A1615}.Release|x86.Build.0 = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.Build.0 = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|ARM.ActiveCfg = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|ARM.Build.0 = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|x64.ActiveCfg = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|x64.Build.0 = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|x86.ActiveCfg = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|x86.Build.0 = Debug|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.ActiveCfg = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|Any CPU.Build.0 = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.ActiveCfg = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|ARM.Build.0 = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.ActiveCfg = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x64.Build.0 = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.ActiveCfg = Release|Any CPU
{226F3575-B683-446D-A2F0-181291DC8787}.Release|x86.Build.0 = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|ARM.Build.0 = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|x64.ActiveCfg = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|x64.Build.0 = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|x86.ActiveCfg = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Debug|x86.Build.0 = Debug|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|Any CPU.Build.0 = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|ARM.ActiveCfg = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|ARM.Build.0 = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|x64.ActiveCfg = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|x64.Build.0 = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|x86.ActiveCfg = Release|Any CPU
{9949326E-9261-4F95-89B1-151F60498951}.Release|x86.Build.0 = Release|Any CPU
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|Any CPU.ActiveCfg = Debug|ARM
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.ActiveCfg = Debug|ARM {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.ActiveCfg = Debug|ARM
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Build.0 = Debug|ARM {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Build.0 = Debug|ARM
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Deploy.0 = Debug|ARM {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Debug|ARM.Deploy.0 = Debug|ARM
@ -189,50 +103,48 @@ Global
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.ActiveCfg = Release|x86 {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.ActiveCfg = Release|x86
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Build.0 = Release|x86 {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Build.0 = Release|x86
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Deploy.0 = Release|x86 {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1}.Release|x86.Deploy.0 = Release|x86
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|ARM.ActiveCfg = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|ARM.ActiveCfg = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|ARM.Build.0 = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|ARM.Build.0 = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x64.ActiveCfg = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x64.ActiveCfg = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x64.Build.0 = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x64.Build.0 = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x86.ActiveCfg = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x86.ActiveCfg = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Debug|x86.Build.0 = Debug|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x86.Build.0 = Debug|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|Any CPU.Build.0 = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|Any CPU.Build.0 = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|ARM.ActiveCfg = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|ARM.ActiveCfg = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|ARM.Build.0 = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|ARM.Build.0 = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x64.ActiveCfg = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x64.ActiveCfg = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x64.Build.0 = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x64.Build.0 = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x86.ActiveCfg = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x86.ActiveCfg = Release|Any CPU
{85AACDB7-959D-406D-A8DF-2F1E013F8F40}.Release|x86.Build.0 = Release|Any CPU {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x86.Build.0 = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|Any CPU.Build.0 = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|ARM.ActiveCfg = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|ARM.Build.0 = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|ARM.Build.0 = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x64.ActiveCfg = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|x64.ActiveCfg = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x64.Build.0 = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|x64.Build.0 = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x86.ActiveCfg = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|x86.ActiveCfg = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Debug|x86.Build.0 = Debug|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Debug|x86.Build.0 = Debug|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|Any CPU.ActiveCfg = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|Any CPU.Build.0 = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|Any CPU.Build.0 = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|ARM.ActiveCfg = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|ARM.ActiveCfg = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|ARM.Build.0 = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|ARM.Build.0 = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x64.ActiveCfg = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|x64.ActiveCfg = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x64.Build.0 = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|x64.Build.0 = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x86.ActiveCfg = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|x86.ActiveCfg = Release|Any CPU
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4}.Release|x86.Build.0 = Release|Any CPU {3FF37D40-F770-45B2-95DD-7A84093E1425}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{C7BF2B18-CC74-430B-BCB2-600304EFA3D8} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17} {A204A102-C745-4D65-AEC8-7B96FAEDEF2D} = {52AECE49-F314-4F76-98F2-FA800F07824B}
{EF44F661-B98A-4676-927F-85D138F82300} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17} {951BC5D2-D653-42D9-9A91-21DC50DE0182} = {52AECE49-F314-4F76-98F2-FA800F07824B}
{F789647E-96F7-43E3-A895-FA3FE8D01260} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17} {F92DA93D-75DB-4308-A5F9-6B4C3908A675} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
{86470440-FEE2-4120-AF5A-3762FB9C536F} = {AE8A7E02-0F7D-41B0-AB23-15394150ED17} {AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
{9949326E-9261-4F95-89B1-151F60498951} = {100879CC-8910-459E-856E-253D629E45DE} {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133} = {6A596588-F93F-47CC-BE5D-58C3B34ADDEB}
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {100879CC-8910-459E-856E-253D629E45DE} {3FF37D40-F770-45B2-95DD-7A84093E1425} = {6A596588-F93F-47CC-BE5D-58C3B34ADDEB}
{85AACDB7-959D-406D-A8DF-2F1E013F8F40} = {100879CC-8910-459E-856E-253D629E45DE}
{7FB616E1-E0D4-48FA-8AFD-60E73FCF32E4} = {100879CC-8910-459E-856E-253D629E45DE}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -1,179 +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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Xml;
#if NETFX_CORE
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
#endif
namespace MapControl
{
/// <summary>
/// Displays Bing Maps tiles. The static ApiKey property must be set to a Bing Maps API Key.
/// Tile image URLs and min/max zoom levels are retrieved from the Imagery Metadata Service
/// (see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
/// </summary>
public class BingMapsTileLayer : MapTileLayer
{
public enum MapMode
{
Road, Aerial, AerialWithLabels
}
public BingMapsTileLayer()
: this(new TileImageLoader())
{
}
public BingMapsTileLayer(ITileImageLoader tileImageLoader)
: base(tileImageLoader)
{
MinZoomLevel = 1;
MaxZoomLevel = 21;
Loaded += OnLoaded;
}
public static string ApiKey { get; set; }
public MapMode Mode { get; set; }
public string Culture { get; set; }
public ImageSource LogoImage { get; set; }
private void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
if (string.IsNullOrEmpty(ApiKey))
{
Debug.WriteLine("BingMapsTileLayer requires a Bing Maps API Key");
}
else
{
var uri = string.Format("http://dev.virtualearth.net/REST/V1/Imagery/Metadata/{0}?output=xml&key={1}", Mode, ApiKey);
var request = WebRequest.CreateHttp(uri);
request.BeginGetResponse(HandleImageryMetadataResponse, request);
}
}
private void HandleImageryMetadataResponse(IAsyncResult asyncResult)
{
try
{
var request = (HttpWebRequest)asyncResult.AsyncState;
using (var response = request.EndGetResponse(asyncResult))
using (var xmlReader = XmlReader.Create(response.GetResponseStream()))
{
ReadImageryMetadataResponse(xmlReader);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private void ReadImageryMetadataResponse(XmlReader xmlReader)
{
string logoUri = null;
string imageUrl = null;
string[] imageUrlSubdomains = null;
int? zoomMin = null;
int? zoomMax = null;
do
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
switch (xmlReader.Name)
{
case "BrandLogoUri":
logoUri = xmlReader.ReadElementContentAsString();
break;
case "ImageUrl":
imageUrl = xmlReader.ReadElementContentAsString();
break;
case "ImageUrlSubdomains":
imageUrlSubdomains = ReadStrings(xmlReader.ReadSubtree());
break;
case "ZoomMin":
zoomMin = xmlReader.ReadElementContentAsInt();
break;
case "ZoomMax":
zoomMax = xmlReader.ReadElementContentAsInt();
break;
default:
xmlReader.Read();
break;
}
}
else
{
xmlReader.Read();
}
}
while (xmlReader.NodeType != XmlNodeType.None);
if (!string.IsNullOrEmpty(imageUrl) && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
{
var op = Dispatcher.BeginInvoke(new Action(() =>
{
if (string.IsNullOrEmpty(Culture))
{
Culture = CultureInfo.CurrentUICulture.Name;
}
TileSource = new BingMapsTileSource(imageUrl.Replace("{culture}", Culture), imageUrlSubdomains);
if (zoomMin.HasValue && zoomMin.Value > MinZoomLevel)
{
MinZoomLevel = zoomMin.Value;
}
if (zoomMax.HasValue && zoomMax.Value < MaxZoomLevel)
{
MaxZoomLevel = zoomMax.Value;
}
if (!string.IsNullOrEmpty(logoUri))
{
LogoImage = new BitmapImage(new Uri(logoUri));
}
}));
}
}
private static string[] ReadStrings(XmlReader xmlReader)
{
var strings = new List<string>();
do
{
if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "string")
{
strings.Add(xmlReader.ReadElementContentAsString());
}
else
{
xmlReader.Read();
}
}
while (xmlReader.NodeType != XmlNodeType.None);
return strings.ToArray();
}
}
}

View file

@ -1,58 +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;
using System.IO;
using System.Net;
using System.Windows.Media.Imaging;
namespace MapControl
{
/// <summary>
/// Creates frozen BitmapSources from Stream, file or Uri.
/// </summary>
public static class BitmapSourceHelper
{
public static BitmapSource FromStream(Stream stream)
{
return BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
public static BitmapSource FromFile(string path)
{
if (!File.Exists(path))
{
return null;
}
using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
return FromStream(fileStream);
}
}
public static BitmapSource FromUri(Uri uri)
{
if (!uri.IsAbsoluteUri)
{
return FromFile(uri.OriginalString);
}
if (uri.Scheme == "file")
{
return FromFile(uri.LocalPath);
}
using (var response = WebRequest.Create(uri).GetResponse())
using (var responseStream = response.GetResponseStream())
using (var memoryStream = new MemoryStream())
{
responseStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
return FromStream(memoryStream);
}
}
}
}

View file

@ -1,31 +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;
using System.ComponentModel;
using System.Globalization;
namespace MapControl
{
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))]
#if !SILVERLIGHT
[Serializable]
#endif
public partial class BoundingBox
{
}
}

View file

@ -1,21 +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.Media.Animation;
namespace MapControl
{
internal static class Extensions
{
public static void BeginAnimation(this DependencyObject obj, DependencyProperty property, Timeline animation)
{
Storyboard.SetTargetProperty(animation, new PropertyPath(property));
Storyboard.SetTarget(animation, obj);
var storyboard = new Storyboard();
storyboard.Children.Add(animation);
storyboard.Begin();
}
}
}

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)
#if NETFX_CORE
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows.Media;
using System.Windows.Media.Imaging;
#endif
namespace MapControl
{
/// <summary>
/// Provides the image of a map tile.
/// ImageTileSource bypasses image downloading and optional caching in TileImageLoader.
/// By overriding the LoadImage method, an application can provide tile images from an arbitrary source.
/// </summary>
public class ImageTileSource : TileSource
{
public virtual ImageSource LoadImage(int x, int y, int zoomLevel)
{
var uri = GetUri(x, y, zoomLevel);
return uri != null ? new BitmapImage(uri) : null;
}
}
}

View file

@ -1,24 +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.Media;
namespace MapControl
{
/// <summary>
/// Provides the image of a map tile.
/// ImageTileSource bypasses image downloading and optional caching in TileImageLoader.
/// By overriding the LoadImage method, an application can provide tile images from an arbitrary source.
/// LoadImage will be called from a non-UI thread and must therefore return a frozen ImageSource.
/// </summary>
public class ImageTileSource : TileSource
{
public virtual ImageSource LoadImage(int x, int y, int zoomLevel)
{
var uri = GetUri(x, y, zoomLevel);
return uri != null ? BitmapSourceHelper.FromUri(uri) : null;
}
}
}

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;
using System.ComponentModel;
using System.Globalization;
namespace MapControl
{
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
{
}
}

View file

@ -1,31 +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;
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))]
#if !SILVERLIGHT
[Serializable]
#endif
public partial class Location
{
}
}

View file

@ -1,70 +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.Input;
namespace MapControl
{
/// <summary>
/// MapBase with default input event handling.
/// </summary>
public class Map : MapBase
{
public static readonly DependencyProperty MouseWheelZoomDeltaProperty = DependencyProperty.Register(
nameof(MouseWheelZoomDelta), typeof(double), typeof(Map), new PropertyMetadata(1d));
private Point? mousePosition;
public Map()
{
MouseWheel += OnMouseWheel;
MouseLeftButtonDown += OnMouseLeftButtonDown;
MouseLeftButtonUp += OnMouseLeftButtonUp;
MouseMove += OnMouseMove;
}
/// <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); }
}
private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
var zoomChange = MouseWheelZoomDelta * e.Delta / 120d;
ZoomMap(e.GetPosition(this), TargetZoomLevel + zoomChange);
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (CaptureMouse())
{
mousePosition = e.GetPosition(this);
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (mousePosition.HasValue)
{
mousePosition = null;
ReleaseMouseCapture();
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (mousePosition.HasValue)
{
var position = e.GetPosition(this);
TranslateMap(new Point(position.X - mousePosition.Value.X, position.Y - mousePosition.Value.Y));
mousePosition = position;
}
}
}
}

View file

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{EB133B78-DEFF-416A-8F0C-89E54D766576}</ProjectGuid>
<ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl</RootNamespace>
<AssemblyName>MapControl.Silverlight</AssemblyName>
<TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
<TargetFrameworkProfile />
</PropertyGroup>
<!-- This property group is only here to support building this project using the
MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs
to set the TargetFrameworkVersion to v3.5 -->
<PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System.Windows" />
<Reference Include="system" />
<Reference Include="System.Core">
<HintPath>$(TargetFrameworkDirectory)System.Core.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AzimuthalEquidistantProjection.cs" />
<Compile Include="AzimuthalProjection.cs" />
<Compile Include="BingMapsTileLayer.cs" />
<Compile Include="BingMapsTileSource.cs" />
<Compile Include="BoundingBox.cs" />
<Compile Include="BoundingBoxConverter.cs" />
<Compile Include="CenteredBoundingBox.cs" />
<Compile Include="EquirectangularProjection.cs" />
<Compile Include="Extensions.Silverlight.cs" />
<Compile Include="GnomonicProjection.cs" />
<Compile Include="HyperlinkText.cs" />
<Compile Include="ImageTileSource.Silverlight.WinRT.cs" />
<Compile Include="Location.cs" />
<Compile Include="LocationCollection.cs" />
<Compile Include="LocationCollectionConverter.cs" />
<Compile Include="LocationConverter.cs" />
<Compile Include="Map.Silverlight.cs" />
<Compile Include="MapBase.cs" />
<Compile Include="MapBase.Silverlight.WinRT.cs" />
<Compile Include="MapImageLayer.cs" />
<Compile Include="MapImageLayer.Silverlight.WinRT.cs" />
<Compile Include="MapGraticule.cs" />
<Compile Include="MapGraticule.Silverlight.WinRT.cs" />
<Compile Include="MapItem.Silverlight.WinRT.cs" />
<Compile Include="MapItemsControl.Silverlight.WinRT.cs" />
<Compile Include="MapOverlay.cs" />
<Compile Include="MapOverlay.Silverlight.WinRT.cs" />
<Compile Include="MapPanel.cs" />
<Compile Include="MapPanel.Silverlight.WinRT.cs" />
<Compile Include="MapPath.cs" />
<Compile Include="MapPath.Silverlight.WinRT.cs" />
<Compile Include="MapPolyline.cs" />
<Compile Include="MapPolyline.Silverlight.WinRT.cs" />
<Compile Include="MapProjection.cs" />
<Compile Include="MapTileLayer.cs" />
<Compile Include="MatrixEx.Silverlight.WinRT.cs" />
<Compile Include="OrthographicProjection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pushpin.Silverlight.WinRT.cs" />
<Compile Include="StereographicProjection.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.Silverlight.WinRT.cs" />
<Compile Include="TileGrid.cs" />
<Compile Include="TileImageLoader.Silverlight.cs" />
<Compile Include="MapTileLayer.Silverlight.WinRT.cs" />
<Compile Include="TileSource.cs" />
<Compile Include="TileSourceConverter.cs" />
<Compile Include="ViewportChangedEventArgs.cs" />
<Compile Include="WebMercatorProjection.cs" />
<Compile Include="WmsImageLayer.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<None Include="..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
<SilverlightProjectProperties />
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<!-- 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>

View file

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
<SilverlightProjectProperties>
<StartPageUrl>
</StartPageUrl>
<StartAction>DynamicPage</StartAction>
<AspNetDebugging>True</AspNetDebugging>
<NativeDebugging>False</NativeDebugging>
<SQLDebugging>False</SQLDebugging>
<ExternalProgram>
</ExternalProgram>
<StartExternalURL>
</StartExternalURL>
<StartCmdLineArguments>
</StartCmdLineArguments>
<StartWorkingDirectory>
</StartWorkingDirectory>
<ShowWebRefOnDebugPrompt>True</ShowWebRefOnDebugPrompt>
<OutOfBrowserProjectToDebug>
</OutOfBrowserProjectToDebug>
<ShowRiaSvcsOnDebugPrompt>True</ShowRiaSvcsOnDebugPrompt>
</SilverlightProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View file

@ -1,135 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.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>{226F3575-B683-446D-A2F0-181291DC8787}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl</RootNamespace>
<AssemblyName>MapControl.WPF</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</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>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Xaml" />
<Reference Include="System.XML" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="AzimuthalEquidistantProjection.cs" />
<Compile Include="AzimuthalProjection.cs" />
<Compile Include="BingMapsTileLayer.cs" />
<Compile Include="BingMapsTileSource.cs" />
<Compile Include="BoundingBox.cs" />
<Compile Include="BoundingBoxConverter.cs" />
<Compile Include="CenteredBoundingBox.cs" />
<Compile Include="EquirectangularProjection.cs" />
<Compile Include="GnomonicProjection.cs" />
<Compile Include="BitmapSourceHelper.cs" />
<Compile Include="HyperlinkText.cs" />
<Compile Include="ImageTileSource.WPF.cs" />
<Compile Include="Location.cs" />
<Compile Include="LocationCollection.cs" />
<Compile Include="LocationCollectionConverter.cs" />
<Compile Include="LocationConverter.cs" />
<Compile Include="Map.WPF.cs" />
<Compile Include="MapBase.cs" />
<Compile Include="MapBase.WPF.cs" />
<Compile Include="MapImageLayer.cs" />
<Compile Include="MapImageLayer.WPF.cs" />
<Compile Include="MapGraticule.cs" />
<Compile Include="MapGraticule.WPF.cs" />
<Compile Include="MapItem.WPF.cs" />
<Compile Include="MapItemsControl.WPF.cs" />
<Compile Include="MapOverlay.cs" />
<Compile Include="MapOverlay.WPF.cs" />
<Compile Include="MapPanel.cs" />
<Compile Include="MapPanel.WPF.cs" />
<Compile Include="MapPath.cs" />
<Compile Include="MapPath.WPF.cs" />
<Compile Include="MapPolyline.cs" />
<Compile Include="MapPolyline.WPF.cs" />
<Compile Include="MapScale.cs" />
<Compile Include="MapProjection.cs" />
<Compile Include="MatrixEx.WPF.cs" />
<Compile Include="OrthographicProjection.cs" />
<Compile Include="StereographicProjection.cs" />
<Compile Include="WebMercatorProjection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pushpin.WPF.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.WPF.cs" />
<Compile Include="TileGrid.cs" />
<Compile Include="TileImageLoader.WPF.cs" />
<Compile Include="MapTileLayer.cs" />
<Compile Include="MapTileLayer.WPF.cs" />
<Compile Include="TileSource.cs" />
<Compile Include="TileSourceConverter.cs" />
<Compile Include="ViewportChangedEventArgs.cs" />
<Compile Include="WmsImageLayer.cs" />
<Compile Include="WmsLayers.WPF.WinRT.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<None Include="..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<!-- 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>

View file

@ -1,69 +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;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MapControl
{
public partial class MapImageLayer
{
protected void UpdateImage(Uri uri)
{
Task.Run(() =>
{
BitmapSource image = null;
try
{
image = BitmapSourceHelper.FromUri(uri);
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", uri, ex.Message);
}
Dispatcher.BeginInvoke(new Action(() => UpdateImage(image)));
});
}
protected void UpdateImage(BitmapSource bitmap)
{
SetTopImage(bitmap);
if (bitmap != null && !bitmap.IsFrozen && bitmap.IsDownloading)
{
bitmap.DownloadCompleted += BitmapDownloadCompleted;
bitmap.DownloadFailed += BitmapDownloadFailed;
}
else
{
SwapImages();
}
}
private void BitmapDownloadCompleted(object sender, EventArgs e)
{
var bitmap = (BitmapSource)sender;
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
bitmap.DownloadFailed -= BitmapDownloadFailed;
SwapImages();
}
private void BitmapDownloadFailed(object sender, ExceptionEventArgs e)
{
var bitmap = (BitmapSource)sender;
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
bitmap.DownloadFailed -= BitmapDownloadFailed;
((Image)Children[topImageIndex]).Source = null;
SwapImages();
}
}
}

View file

@ -1,82 +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;
#if NETFX_CORE
using Windows.Foundation;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
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)
{
return new Matrix(1d, 0d, 0d, 1d, -translation1X, -translation1Y)
.Scale(scaleX, scaleY)
.Rotate(rotationAngle)
.Translate(translation2X, translation2Y);
}
private static Matrix Translate(this Matrix matrix, double offsetX, double offsetY)
{
matrix.OffsetX += offsetX;
matrix.OffsetY += offsetY;
return matrix;
}
private static Matrix Scale(this Matrix matrix, double scaleX, double scaleY)
{
return Multiply(matrix, new Matrix(scaleX, 0d, 0d, scaleY, 0d, 0d));
}
private static Matrix Rotate(this Matrix matrix, double angle)
{
if (angle == 0d)
{
return matrix;
}
angle = (angle % 360d) / 180d * Math.PI;
var cos = Math.Cos(angle);
var sin = Math.Sin(angle);
return Multiply(matrix, new Matrix(cos, sin, -sin, cos, 0d, 0d));
}
private static Matrix Invert(this Matrix matrix)
{
var determinant = matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21;
return new Matrix(
matrix.M22 / determinant,
-matrix.M12 / determinant,
-matrix.M21 / determinant,
matrix.M11 / determinant,
(matrix.M21 * matrix.OffsetY - matrix.M22 * matrix.OffsetX) / determinant,
(matrix.M12 * matrix.OffsetX - matrix.M11 * matrix.OffsetY) / determinant);
}
private static Matrix Multiply(this Matrix matrix1, Matrix matrix2)
{
return new Matrix(
matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21,
matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22,
matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21,
matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22,
(matrix2.M11 * matrix1.OffsetX + matrix2.M21 * matrix1.OffsetY) + matrix2.OffsetX,
(matrix2.M12 * matrix1.OffsetX + matrix2.M22 * matrix1.OffsetY) + matrix2.OffsetY);
}
}
}

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;

View file

@ -4,7 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;
@ -27,7 +27,7 @@ namespace MapControl
public override double GetViewportScale(double zoomLevel) public override double GetViewportScale(double zoomLevel)
{ {
return base.GetViewportScale(zoomLevel) / MetersPerDegree; return DegreesToViewportScale(zoomLevel) / MetersPerDegree;
} }
public override Point GetMapScale(Location location) public override Point GetMapScale(Location location)

View file

@ -0,0 +1,138 @@
// 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.Diagnostics;
using System.Globalization;
using System.Linq;
#if WINDOWS_UWP
using Windows.Data.Xml.Dom;
using Windows.UI.Xaml;
#else
using System.Windows;
using System.Xml;
#endif
namespace MapControl
{
/// <summary>
/// Displays Bing Maps tiles. The static ApiKey property must be set to a Bing Maps API Key.
/// Tile image URLs and min/max zoom levels are retrieved from the Imagery Metadata Service
/// (see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
/// </summary>
public class BingMapsTileLayer : MapTileLayer
{
public enum MapMode
{
Road, Aerial, AerialWithLabels
}
public BingMapsTileLayer()
: this(new TileImageLoader())
{
}
public BingMapsTileLayer(ITileImageLoader tileImageLoader)
: base(tileImageLoader)
{
MinZoomLevel = 1;
MaxZoomLevel = 21;
Loaded += OnLoaded;
}
public static string ApiKey { get; set; }
public MapMode Mode { get; set; }
public string Culture { get; set; }
public Uri LogoImageUri { get; set; }
private async void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
if (string.IsNullOrEmpty(ApiKey))
{
Debug.WriteLine("BingMapsTileLayer requires a Bing Maps API Key");
return;
}
var imageryMetadataUrl = "http://dev.virtualearth.net/REST/V1/Imagery/Metadata/" + Mode;
try
{
var document = await XmlDocument.LoadFromUriAsync(new Uri(imageryMetadataUrl + "?output=xml&key=" + ApiKey));
var imageryMetadata = document.DocumentElement.GetElementsByTagName("ImageryMetadata").OfType<XmlElement>().FirstOrDefault();
if (imageryMetadata != null)
{
ReadImageryMetadata(imageryMetadata);
}
var brandLogoUri = document.DocumentElement.GetElementsByTagName("BrandLogoUri").OfType<XmlElement>().FirstOrDefault();
if (brandLogoUri != null)
{
LogoImageUri = new Uri(brandLogoUri.InnerText);
}
}
catch (Exception ex)
{
Debug.WriteLine("BingMapsTileLayer: {0}: {1}", imageryMetadataUrl, ex.Message);
}
}
private void ReadImageryMetadata(XmlElement imageryMetadata)
{
string imageUrl = null;
string[] imageUrlSubdomains = null;
int? zoomMin = null;
int? zoomMax = null;
foreach (var element in imageryMetadata.ChildNodes.OfType<XmlElement>())
{
switch ((string)element.LocalName)
{
case "ImageUrl":
imageUrl = element.InnerText;
break;
case "ImageUrlSubdomains":
imageUrlSubdomains = element.ChildNodes
.OfType<XmlElement>()
.Where(e => (string)e.LocalName == "string")
.Select(e => e.InnerText)
.ToArray();
break;
case "ZoomMin":
zoomMin = int.Parse(element.InnerText);
break;
case "ZoomMax":
zoomMax = int.Parse(element.InnerText);
break;
default:
break;
}
}
if (!string.IsNullOrEmpty(imageUrl) && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
{
if (zoomMin.HasValue && zoomMin.Value > MinZoomLevel)
{
MinZoomLevel = zoomMin.Value;
}
if (zoomMax.HasValue && zoomMax.Value < MaxZoomLevel)
{
MaxZoomLevel = zoomMax.Value;
}
if (string.IsNullOrEmpty(Culture))
{
Culture = CultureInfo.CurrentUICulture.Name;
}
TileSource = new BingMapsTileSource(imageUrl.Replace("{culture}", Culture), imageUrlSubdomains);
}
}
}
}

View file

@ -6,7 +6,7 @@ using System;
namespace MapControl namespace MapControl
{ {
internal class BingMapsTileSource : TileSource public class BingMapsTileSource : TileSource
{ {
private readonly string[] subdomains; private readonly string[] subdomains;

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;

View file

@ -5,7 +5,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents; using Windows.UI.Xaml.Documents;
@ -43,9 +43,7 @@ namespace MapControl
var link = new Hyperlink { NavigateUri = uri }; var link = new Hyperlink { NavigateUri = uri };
link.Inlines.Add(new Run { Text = match.Groups[1].Value }); link.Inlines.Add(new Run { Text = match.Groups[1].Value });
#if SILVERLIGHT #if !WINDOWS_UWP
link.TargetName = "_blank";
#elif !NETFX_CORE
link.ToolTip = uri.ToString(); link.ToolTip = uri.ToString();
link.RequestNavigate += (s, e) => System.Diagnostics.Process.Start(e.Uri.ToString()); link.RequestNavigate += (s, e) => System.Diagnostics.Process.Start(e.Uri.ToString());
#endif #endif
@ -86,16 +84,7 @@ namespace MapControl
{ {
inlines = ((Paragraph)obj).Inlines; inlines = ((Paragraph)obj).Inlines;
} }
#if NETFX_CORE || SILVERLIGHT
else if (obj is RichTextBlock)
{
var paragraph = new Paragraph();
inlines = paragraph.Inlines;
var richTextBlock = (RichTextBlock)obj;
richTextBlock.Blocks.Clear();
richTextBlock.Blocks.Add(paragraph);
}
#endif
if (inlines != null) if (inlines != null)
{ {
inlines.Clear(); inlines.Clear();

View file

@ -39,10 +39,9 @@ namespace MapControl
public bool Equals(Location location) public bool Equals(Location location)
{ {
return ReferenceEquals(this, location) return location != null
|| (location != null && Math.Abs(location.latitude - latitude) < 1e-9
&& location.latitude == latitude && Math.Abs(location.longitude - longitude) < 1e-9;
&& location.longitude == longitude);
} }
public override bool Equals(object obj) public override bool Equals(object obj)

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.UI.Xaml; using Windows.UI.Xaml;
#else #else
using System.Windows; using System.Windows;
@ -30,7 +30,7 @@ namespace MapControl
private double GetLineDistance() private double GetLineDistance()
{ {
var minDistance = MinLineDistance * 360d / (Math.Pow(2d, ParentMap.ZoomLevel) * TileSource.TileSize); var minDistance = MinLineDistance / MapProjection.DegreesToViewportScale(ParentMap.ZoomLevel);
var scale = 1d; var scale = 1d;
if (minDistance < 1d) if (minDistance < 1d)

View file

@ -4,7 +4,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
@ -279,7 +279,7 @@ namespace MapControl
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.WriteLine(ex.Message); Debug.WriteLine("MapImageLayer: " + ex.Message);
} }
if (!imageUpdated) if (!imageUpdated)
@ -295,12 +295,12 @@ namespace MapControl
/// </summary> /// </summary>
protected abstract bool UpdateImage(BoundingBox boundingBox); protected abstract bool UpdateImage(BoundingBox boundingBox);
private void SetTopImage(BitmapSource bitmap) private void SetTopImage(BitmapSource bitmapSource)
{ {
topImageIndex = (topImageIndex + 1) % 2; topImageIndex = (topImageIndex + 1) % 2;
var topImage = (Image)Children[topImageIndex]; var topImage = (Image)Children[topImageIndex];
topImage.Source = bitmap; topImage.Source = bitmapSource;
SetBoundingBox(topImage, boundingBox?.Clone()); SetBoundingBox(topImage, boundingBox?.Clone());
} }

View file

@ -2,7 +2,7 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE #if WINDOWS_UWP
using Windows.UI.Text; using Windows.UI.Text;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else #else

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;

View file

@ -2,7 +2,7 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE #if WINDOWS_UWP
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else #else

View file

@ -4,11 +4,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else #else
using System.ComponentModel;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
#endif #endif
@ -28,18 +27,6 @@ namespace MapControl
nameof(IsClosed), typeof(bool), typeof(MapPolyline), nameof(IsClosed), typeof(bool), typeof(MapPolyline),
new PropertyMetadata(false, (o, e) => ((MapPolyline)o).UpdateData())); new PropertyMetadata(false, (o, e) => ((MapPolyline)o).UpdateData()));
/// <summary>
/// Gets or sets the locations that define the polyline points.
/// </summary>
#if !NETFX_CORE
[TypeConverter(typeof(LocationCollectionConverter))]
#endif
public IEnumerable<Location> Locations
{
get { return (IEnumerable<Location>)GetValue(LocationsProperty); }
set { SetValue(LocationsProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets a value that indicates if the polyline is closed, i.e. is a polygon. /// Gets or sets a value that indicates if the polyline is closed, i.e. is a polygon.
/// </summary> /// </summary>

View file

@ -4,7 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else #else
@ -15,14 +15,22 @@ using System.Windows.Media;
namespace MapControl namespace MapControl
{ {
/// <summary> /// <summary>
/// Defines a map projection between geographic coordinates and cartesian map coordinates /// Defines a map projection between geographic coordinates, cartesian map coordinates and viewport coordinates.
/// and viewport coordinates, i.e. pixels.
/// </summary> /// </summary>
public abstract partial class MapProjection public abstract class MapProjection
{ {
public const int TileSize = 256;
public const double Wgs84EquatorialRadius = 6378137d; public const double Wgs84EquatorialRadius = 6378137d;
public const double MetersPerDegree = Wgs84EquatorialRadius * Math.PI / 180d; public const double MetersPerDegree = Wgs84EquatorialRadius * Math.PI / 180d;
/// <summary>
/// Gets the scaling factor from cartesian map coordinates in degrees to viewport coordinates for the specified zoom level.
/// </summary>
public static double DegreesToViewportScale(double zoomLevel)
{
return Math.Pow(2d, zoomLevel) * TileSize / 360d;
}
/// <summary> /// <summary>
/// Gets or sets the WMS 1.3.0 CRS Identifier. /// Gets or sets the WMS 1.3.0 CRS Identifier.
/// </summary> /// </summary>
@ -64,7 +72,7 @@ namespace MapControl
/// </summary> /// </summary>
public virtual double GetViewportScale(double zoomLevel) public virtual double GetViewportScale(double zoomLevel)
{ {
return Math.Pow(2d, zoomLevel) * TileSource.TileSize / 360d; return DegreesToViewportScale(zoomLevel);
} }
/// <summary> /// <summary>
@ -142,7 +150,7 @@ namespace MapControl
var center = LocationToPoint(mapCenter); var center = LocationToPoint(mapCenter);
ViewportTransform.Matrix = MatrixEx.TranslateScaleRotateTranslate( ViewportTransform.Matrix = MatrixEx.TranslateScaleRotateTranslate(
center.X, center.Y, ViewportScale, -ViewportScale, heading, viewportCenter.X, viewportCenter.Y); -center.X, -center.Y, ViewportScale, -ViewportScale, heading, viewportCenter.X, viewportCenter.Y);
} }
/// <summary> /// <summary>

View file

@ -5,16 +5,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else #else
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
#endif #endif
@ -29,11 +27,6 @@ namespace MapControl
/// <summary> /// <summary>
/// Fills the map viewport with map tiles from a TileSource. /// Fills the map viewport with map tiles from a TileSource.
/// </summary> /// </summary>
#if NETFX_CORE
[ContentProperty(Name = "TileSource")]
#else
[ContentProperty("TileSource")]
#endif
public partial class MapTileLayer : Panel, IMapLayer public partial class MapTileLayer : Panel, IMapLayer
{ {
/// <summary> /// <summary>
@ -253,9 +246,9 @@ namespace MapControl
{ {
foreach (var tile in Tiles) foreach (var tile in Tiles)
{ {
var tileSize = TileSource.TileSize << (TileGrid.ZoomLevel - tile.ZoomLevel); var tileSize = MapProjection.TileSize << (TileGrid.ZoomLevel - tile.ZoomLevel);
var x = tileSize * tile.X - TileSource.TileSize * TileGrid.XMin; var x = tileSize * tile.X - MapProjection.TileSize * TileGrid.XMin;
var y = tileSize * tile.Y - TileSource.TileSize * TileGrid.YMin; var y = tileSize * tile.Y - MapProjection.TileSize * TileGrid.YMin;
tile.Image.Width = tileSize; tile.Image.Width = tileSize;
tile.Image.Height = tileSize; tile.Image.Height = tileSize;
@ -322,8 +315,8 @@ namespace MapControl
private TileGrid GetTileGrid() private TileGrid GetTileGrid()
{ {
var tileZoomLevel = Math.Max(0, (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset)); var tileZoomLevel = Math.Max(0, (int)Math.Round(parentMap.ZoomLevel + ZoomLevelOffset));
var tileScale = (1 << tileZoomLevel); var tileScale = (double)(1 << tileZoomLevel);
var scale = tileScale / (Math.Pow(2d, parentMap.ZoomLevel) * TileSource.TileSize); var scale = tileScale / (Math.Pow(2d, parentMap.ZoomLevel) * MapProjection.TileSize);
var tileCenterX = tileScale * (0.5 + parentMap.Center.Longitude / 360d); var tileCenterX = tileScale * (0.5 + parentMap.Center.Longitude / 360d);
var tileCenterY = tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d); var tileCenterY = tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d);
var viewCenterX = parentMap.RenderSize.Width / 2d; var viewCenterX = parentMap.RenderSize.Width / 2d;
@ -331,7 +324,7 @@ namespace MapControl
var transform = new MatrixTransform var transform = new MatrixTransform
{ {
Matrix = MatrixEx.TranslateScaleRotateTranslate(viewCenterX, viewCenterY, scale, scale, -parentMap.Heading, tileCenterX, tileCenterY) Matrix = MatrixEx.TranslateScaleRotateTranslate(-viewCenterX, -viewCenterY, scale, scale, -parentMap.Heading, tileCenterX, tileCenterY)
}; };
var bounds = transform.TransformBounds(new Rect(0d, 0d, parentMap.RenderSize.Width, parentMap.RenderSize.Height)); var bounds = transform.TransformBounds(new Rect(0d, 0d, parentMap.RenderSize.Width, parentMap.RenderSize.Height));
@ -343,17 +336,17 @@ namespace MapControl
private void SetRenderTransform() private void SetRenderTransform()
{ {
var tileScale = (1 << TileGrid.ZoomLevel); var tileScale = (double)(1 << TileGrid.ZoomLevel);
var scale = Math.Pow(2d, parentMap.ZoomLevel) / tileScale; var scale = Math.Pow(2d, parentMap.ZoomLevel) / tileScale;
var tileCenterX = tileScale * (0.5 + parentMap.Center.Longitude / 360d); var tileCenterX = tileScale * (0.5 + parentMap.Center.Longitude / 360d);
var tileCenterY = tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d); var tileCenterY = tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d);
var tileOriginX = TileSource.TileSize * (tileCenterX - TileGrid.XMin); var tileOriginX = MapProjection.TileSize * (tileCenterX - TileGrid.XMin);
var tileOriginY = TileSource.TileSize * (tileCenterY - TileGrid.YMin); var tileOriginY = MapProjection.TileSize * (tileCenterY - TileGrid.YMin);
var viewCenterX = parentMap.RenderSize.Width / 2d; var viewCenterX = parentMap.RenderSize.Width / 2d;
var viewCenterY = parentMap.RenderSize.Height / 2d; var viewCenterY = parentMap.RenderSize.Height / 2d;
((MatrixTransform)RenderTransform).Matrix = MatrixEx.TranslateScaleRotateTranslate( ((MatrixTransform)RenderTransform).Matrix = MatrixEx.TranslateScaleRotateTranslate(
tileOriginX, tileOriginY, scale, scale, parentMap.Heading, viewCenterX, viewCenterY); -tileOriginX, -tileOriginY, scale, scale, parentMap.Heading, viewCenterX, viewCenterY);
} }
private void UpdateTiles() private void UpdateTiles()

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
#else #else
using System.Windows.Controls; using System.Windows.Controls;

View file

@ -25,13 +25,12 @@ namespace MapControl
public bool Equals(TileGrid tileGrid) public bool Equals(TileGrid tileGrid)
{ {
return ReferenceEquals(this, tileGrid) return tileGrid != null
|| (tileGrid != null
&& tileGrid.ZoomLevel == ZoomLevel && tileGrid.ZoomLevel == ZoomLevel
&& tileGrid.XMin == XMin && tileGrid.XMin == XMin
&& tileGrid.YMin == YMin && tileGrid.YMin == YMin
&& tileGrid.XMax == XMax && tileGrid.XMax == XMax
&& tileGrid.YMax == YMax); && tileGrid.YMax == YMax;
} }
public override bool Equals(object obj) public override bool Equals(object obj)

View file

@ -0,0 +1,172 @@
// 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.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
#if WINDOWS_UWP
using Windows.Web.Http;
#else
using System.Net.Http;
#endif
namespace MapControl
{
/// <summary>
/// Loads and optionally caches map tile images for a MapTileLayer.
/// </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.
/// </summary>
public static TimeSpan DefaultCacheExpiration { get; set; } = TimeSpan.FromDays(1);
/// <summary>
/// Minimum expiration time for cached tile images. The default value is one hour.
/// </summary>
public static TimeSpan MinimumCacheExpiration { get; set; } = TimeSpan.FromHours(1);
/// <summary>
/// Maximum expiration time for cached tile images. The default value is one week.
/// </summary>
public static TimeSpan MaximumCacheExpiration { get; set; } = TimeSpan.FromDays(7);
/// <summary>
/// Format string for creating cache keys from the SourceName property of a TileSource,
/// the ZoomLevel, XIndex, and Y properties of a Tile, and the image file extension.
/// The default value is "{0};{1};{2};{3}{4}".
/// </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)
{
pendingTiles.Clear();
var tileSource = tileLayer.TileSource;
var sourceName = tileLayer.SourceName;
var tiles = tileLayer.Tiles.Where(t => t.Pending);
if (tileSource != null && tiles.Any())
{
if (Cache == null || string.IsNullOrEmpty(sourceName) ||
tileSource.UriFormat == null || !tileSource.UriFormat.StartsWith("http"))
{
// no caching, load tile images in UI thread
foreach (var tile in tiles)
{
LoadTileImage(tileSource, tile);
}
}
else
{
pendingTiles.PushRange(tiles.Reverse().ToArray());
while (taskCount < Math.Min(pendingTiles.Count, tileLayer.MaxParallelDownloads))
{
Interlocked.Increment(ref taskCount);
var task = Task.Run(async () => // do not await
{
await LoadPendingTilesAsync(tileSource, sourceName); // run multiple times in parallel
Interlocked.Decrement(ref taskCount);
});
}
}
}
}
private void LoadTileImage(TileSource tileSource, Tile tile)
{
tile.Pending = false;
try
{
var imageSource = tileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
if (imageSource != null)
{
tile.SetImage(imageSource);
}
}
catch (Exception ex)
{
Debug.WriteLine("TileImageLoader: {0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
}
}
private async Task LoadPendingTilesAsync(TileSource tileSource, string sourceName)
{
Tile tile;
while (pendingTiles.TryPop(out tile))
{
tile.Pending = false;
try
{
var uri = tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel);
if (uri != null)
{
var extension = Path.GetExtension(uri.LocalPath);
if (string.IsNullOrEmpty(extension) || extension == ".jpeg")
{
extension = ".jpg";
}
var cacheKey = string.Format(CacheKeyFormat, sourceName, tile.ZoomLevel, tile.XIndex, tile.Y, extension);
await LoadTileImageAsync(tile, uri, cacheKey);
}
}
catch (Exception ex)
{
Debug.WriteLine("TileImageLoader: {0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
}
}
}
private static DateTime GetExpiration(HttpResponseMessage response)
{
var expiration = DefaultCacheExpiration;
var headers = response.Headers;
if (headers.CacheControl != null && headers.CacheControl.MaxAge.HasValue)
{
expiration = headers.CacheControl.MaxAge.Value;
if (expiration < MinimumCacheExpiration)
{
expiration = MinimumCacheExpiration;
}
else if (expiration > MaximumCacheExpiration)
{
expiration = MaximumCacheExpiration;
}
}
return DateTime.UtcNow.Add(expiration);
}
}
}

View file

@ -4,16 +4,21 @@
using System; using System;
using System.Globalization; 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 namespace MapControl
{ {
/// <summary> /// <summary>
/// Provides the URI of a map tile. /// Provides the download Uri or ImageSource of map tiles.
/// </summary> /// </summary>
public partial class TileSource public partial class TileSource
{ {
public const int TileSize = 256;
private Func<int, int, int, Uri> getUri; private Func<int, int, int, Uri> getUri;
private string uriFormat = string.Empty; private string uriFormat = string.Empty;
@ -26,6 +31,9 @@ namespace MapControl
this.uriFormat = uriFormat; this.uriFormat = uriFormat;
} }
/// <summary>
/// Gets or sets the format string to produce tile Uris.
/// </summary>
public string UriFormat public string UriFormat
{ {
get { return uriFormat; } get { return uriFormat; }
@ -76,11 +84,25 @@ namespace MapControl
} }
} }
/// <summary>
/// Gets the map tile Uri.
/// </summary>
public virtual Uri GetUri(int x, int y, int zoomLevel) public virtual Uri GetUri(int x, int y, int zoomLevel)
{ {
return getUri?.Invoke(x, y, zoomLevel); 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) private Uri GetBasicUri(int x, int y, int zoomLevel)
{ {
return new Uri(uriFormat return new Uri(uriFormat
@ -170,8 +192,8 @@ namespace MapControl
.Replace("{S}", south.ToString(CultureInfo.InvariantCulture)) .Replace("{S}", south.ToString(CultureInfo.InvariantCulture))
.Replace("{E}", east.ToString(CultureInfo.InvariantCulture)) .Replace("{E}", east.ToString(CultureInfo.InvariantCulture))
.Replace("{N}", north.ToString(CultureInfo.InvariantCulture)) .Replace("{N}", north.ToString(CultureInfo.InvariantCulture))
.Replace("{X}", TileSize.ToString()) .Replace("{X}", MapProjection.TileSize.ToString())
.Replace("{Y}", TileSize.ToString())); .Replace("{Y}", MapProjection.TileSize.ToString()));
} }
private Uri GetLatLonBoundingBoxUri(int x, int y, int zoomLevel) private Uri GetLatLonBoundingBoxUri(int x, int y, int zoomLevel)
@ -187,8 +209,8 @@ namespace MapControl
.Replace("{s}", south.ToString(CultureInfo.InvariantCulture)) .Replace("{s}", south.ToString(CultureInfo.InvariantCulture))
.Replace("{e}", east.ToString(CultureInfo.InvariantCulture)) .Replace("{e}", east.ToString(CultureInfo.InvariantCulture))
.Replace("{n}", north.ToString(CultureInfo.InvariantCulture)) .Replace("{n}", north.ToString(CultureInfo.InvariantCulture))
.Replace("{X}", TileSize.ToString()) .Replace("{X}", MapProjection.TileSize.ToString())
.Replace("{Y}", TileSize.ToString())); .Replace("{Y}", MapProjection.TileSize.ToString()));
} }
} }
} }

View file

@ -3,7 +3,7 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE #if WINDOWS_UWP
using Windows.Foundation; using Windows.Foundation;
#else #else
using System.Windows; using System.Windows;
@ -34,7 +34,7 @@ namespace MapControl
public override double GetViewportScale(double zoomLevel) public override double GetViewportScale(double zoomLevel)
{ {
return base.GetViewportScale(zoomLevel) / MetersPerDegree; return DegreesToViewportScale(zoomLevel) / MetersPerDegree;
} }
public override Point GetMapScale(Location location) public override Point GetMapScale(Location location)
@ -70,6 +70,8 @@ namespace MapControl
public static double LatitudeToY(double latitude) public static double LatitudeToY(double latitude)
{ {
var lat = latitude * Math.PI / 180d;
return latitude <= -90d ? double.NegativeInfinity return latitude <= -90d ? double.NegativeInfinity
: latitude >= 90d ? double.PositiveInfinity : latitude >= 90d ? double.PositiveInfinity
: Math.Log(Math.Tan((latitude + 90d) * Math.PI / 360d)) / Math.PI * 180d; : Math.Log(Math.Tan((latitude + 90d) * Math.PI / 360d)) / Math.PI * 180d;

View file

@ -3,10 +3,16 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
#if WINDOWS_UWP
using Windows.Data.Xml.Dom;
using Windows.UI.Xaml; using Windows.UI.Xaml;
#else #else
using System.Windows; using System.Windows;
using System.Xml;
#endif #endif
namespace MapControl namespace MapControl
@ -23,15 +29,11 @@ namespace MapControl
public static readonly DependencyProperty LayersProperty = DependencyProperty.Register( public static readonly DependencyProperty LayersProperty = DependencyProperty.Register(
nameof(Layers), typeof(string), typeof(WmsImageLayer), nameof(Layers), typeof(string), typeof(WmsImageLayer),
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage())); new PropertyMetadata(string.Empty, (o, e) => ((WmsImageLayer)o).UpdateImage()));
public static readonly DependencyProperty StylesProperty = DependencyProperty.Register( public static readonly DependencyProperty StylesProperty = DependencyProperty.Register(
nameof(Styles), typeof(string), typeof(WmsImageLayer), nameof(Styles), typeof(string), typeof(WmsImageLayer),
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage())); new PropertyMetadata(string.Empty, (o, e) => ((WmsImageLayer)o).UpdateImage()));
public static readonly DependencyProperty ParametersProperty = DependencyProperty.Register(
nameof(Parameters), typeof(string), typeof(WmsImageLayer),
new PropertyMetadata(null, (o, e) => ((WmsImageLayer)o).UpdateImage()));
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register( public static readonly DependencyProperty FormatProperty = DependencyProperty.Register(
nameof(Format), typeof(string), typeof(WmsImageLayer), nameof(Format), typeof(string), typeof(WmsImageLayer),
@ -67,12 +69,6 @@ namespace MapControl
set { SetValue(StylesProperty, value); } set { SetValue(StylesProperty, value); }
} }
public string Parameters
{
get { return (string)GetValue(ParametersProperty); }
set { SetValue(ParametersProperty, value); }
}
public string Format public string Format
{ {
get { return (string)GetValue(FormatProperty); } get { return (string)GetValue(FormatProperty); }
@ -92,14 +88,60 @@ namespace MapControl
return false; return false;
} }
var version = Version ?? "1.3.0"; var projectionParameters = ParentMap.MapProjection.WmsQueryParameters(boundingBox, Version);
var queryParameters = ParentMap.MapProjection.WmsQueryParameters(boundingBox, version);
if (string.IsNullOrEmpty(queryParameters)) if (string.IsNullOrEmpty(projectionParameters))
{ {
return false; return false;
} }
UpdateImage(GetRequestUri("GetMap"
+ "&LAYERS=" + Layers + "&STYLES=" + Styles + "&FORMAT=" + Format
+ "&TRANSPARENT=" + (Transparent ? "TRUE" : "FALSE") + "&" + projectionParameters));
return true;
}
public async Task<IList<string>> GetLayerNamesAsync()
{
if (ServerUri == null)
{
return null;
}
var layerNames = new List<string>();
try
{
var document = await XmlDocument.LoadFromUriAsync(GetRequestUri("GetCapabilities"));
var capability = ChildElements(document.DocumentElement, "Capability").FirstOrDefault();
if (capability != null)
{
var rootLayer = ChildElements(capability, "Layer").FirstOrDefault();
if (rootLayer != null)
{
foreach (var layer in ChildElements(rootLayer, "Layer"))
{
var name = ChildElements(layer, "Name").FirstOrDefault();
if (name != null)
{
layerNames.Add(name.InnerText);
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine("WmsImageLayer: {0}: {1}", ServerUri, ex.Message);
}
return layerNames;
}
private Uri GetRequestUri(string query)
{
var uri = ServerUri.ToString(); var uri = ServerUri.ToString();
if (!uri.EndsWith("?") && !uri.EndsWith("&")) if (!uri.EndsWith("?") && !uri.EndsWith("&"))
@ -107,22 +149,14 @@ namespace MapControl
uri += "?"; uri += "?";
} }
uri += "SERVICE=WMS" uri += "SERVICE=WMS&VERSION=" + Version + "&REQUEST=" + query;
+ "&VERSION=" + version
+ "&REQUEST=GetMap"
+ "&LAYERS=" + (Layers ?? string.Empty)
+ "&STYLES=" + (Styles ?? string.Empty)
+ "&" + queryParameters
+ "&FORMAT=" + (Format ?? "image/png")
+ "&TRANSPARENT=" + (Transparent ? "TRUE" : "FALSE");
if (!string.IsNullOrEmpty(Parameters)) return new Uri(uri.Replace(" ", "%20"));
{
uri += "&" + Parameters;
} }
UpdateImage(new Uri(uri.Replace(" ", "%20"))); private static IEnumerable<XmlElement> ChildElements(XmlElement element, string name)
return true; {
return element.ChildNodes.OfType<XmlElement>().Where(e => (string)e.LocalName == name);
} }
} }
} }

View file

@ -1,53 +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;
using System.Linq;
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MapControl
{
/// <summary>
/// Loads map tile images.
/// </summary>
public class TileImageLoader : ITileImageLoader
{
public void LoadTiles(MapTileLayer tileLayer)
{
var tileSource = tileLayer.TileSource;
var imageTileSource = tileSource as ImageTileSource;
foreach (var tile in tileLayer.Tiles.Where(t => t.Pending))
{
tile.Pending = false;
try
{
ImageSource image = null;
Uri uri;
if (imageTileSource != null)
{
image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
}
else if ((uri = tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel)) != null)
{
image = new BitmapImage(uri);
}
if (image != null)
{
tile.SetImage(image);
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
}
}
}
}
}

View file

@ -1,272 +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;
using System.Collections.Concurrent;
using System.Diagnostics;
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;
namespace MapControl
{
/// <summary>
/// Loads map tile images and optionally caches them in a System.Runtime.Caching.ObjectCache.
/// </summary>
public class TileImageLoader : ITileImageLoader
{
/// <summary>
/// Default name of an ObjectCache instance that is assigned to the Cache property.
/// </summary>
public const string DefaultCacheName = "TileCache";
/// <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");
/// <summary>
/// Default expiration time for cached tile images. Used when no expiration time
/// was transmitted on download. The default value is one day.
/// </summary>
public static TimeSpan DefaultCacheExpiration { get; set; }
/// <summary>
/// Minimum expiration time for cached tile images. Used when an unnecessarily small expiration time
/// was transmitted on download (e.g. Cache-Control: max-age=0). The default value is one hour.
/// </summary>
public static TimeSpan MinimumCacheExpiration { get; set; }
/// <summary>
/// The ObjectCache used to cache tile images. The default is MemoryCache.Default.
/// </summary>
public static ObjectCache Cache { get; set; }
/// <summary>
/// Optional value to be used for the HttpWebRequest.UserAgent property. The default is null.
/// </summary>
public static string HttpUserAgent { get; set; }
static TileImageLoader()
{
DefaultCacheExpiration = TimeSpan.FromDays(1);
MinimumCacheExpiration = TimeSpan.FromHours(1);
Cache = MemoryCache.Default;
}
private readonly ConcurrentStack<Tile> pendingTiles = new ConcurrentStack<Tile>();
private int taskCount;
public void LoadTiles(MapTileLayer tileLayer)
{
pendingTiles.Clear();
var tiles = tileLayer.Tiles.Where(t => t.Pending);
if (tiles.Any())
{
pendingTiles.PushRange(tiles.Reverse().ToArray());
var tileSource = tileLayer.TileSource;
var sourceName = tileLayer.SourceName;
var maxDownloads = tileLayer.MaxParallelDownloads;
while (taskCount < Math.Min(pendingTiles.Count, maxDownloads))
{
Interlocked.Increment(ref taskCount);
Task.Run(() =>
{
LoadPendingTiles(tileSource, sourceName);
Interlocked.Decrement(ref taskCount);
});
}
}
}
private void LoadPendingTiles(TileSource tileSource, string sourceName)
{
var imageTileSource = tileSource as ImageTileSource;
Tile tile;
while (pendingTiles.TryPop(out tile))
{
tile.Pending = false;
try
{
ImageSource image = null;
Uri uri;
if (imageTileSource != null)
{
image = imageTileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
}
else if ((uri = tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel)) != null)
{
image = LoadImage(uri, sourceName, tile.XIndex, tile.Y, tile.ZoomLevel);
}
if (image != null)
{
tile.SetImage(image);
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
}
}
}
private ImageSource LoadImage(Uri uri, string sourceName, int x, int y, int zoomLevel)
{
ImageSource image = null;
try
{
if (!uri.IsAbsoluteUri)
{
image = BitmapSourceHelper.FromFile(uri.OriginalString);
}
else if (uri.Scheme == "file")
{
image = BitmapSourceHelper.FromFile(uri.LocalPath);
}
else if (Cache == null || string.IsNullOrEmpty(sourceName))
{
image = DownloadImage(uri, null);
}
else
{
var cacheKey = string.Format("{0}/{1}/{2}/{3}", sourceName, zoomLevel, x, y);
if (!GetCachedImage(cacheKey, ref image))
{
// Either no cached image was found or expiration time has expired.
// If download fails use possibly cached but expired image anyway.
image = DownloadImage(uri, cacheKey);
}
}
}
catch (WebException ex)
{
Debug.WriteLine("{0}: {1}: {2}", uri, ex.Status, ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", uri, ex.Message);
}
return image;
}
private static ImageSource DownloadImage(Uri uri, string cacheKey)
{
ImageSource image = null;
var request = WebRequest.CreateHttp(uri);
if (HttpUserAgent != null)
{
request.UserAgent = HttpUserAgent;
}
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.Headers["X-VE-Tile-Info"] != "no-tile") // set by Bing Maps
{
using (var responseStream = response.GetResponseStream())
using (var memoryStream = new MemoryStream())
{
responseStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
image = BitmapSourceHelper.FromStream(memoryStream);
if (cacheKey != null)
{
SetCachedImage(cacheKey, memoryStream, GetExpiration(response.Headers));
}
}
}
}
return image;
}
private static bool GetCachedImage(string cacheKey, ref ImageSource image)
{
var result = false;
var buffer = Cache.Get(cacheKey) as byte[];
if (buffer != null)
{
try
{
using (var memoryStream = new MemoryStream(buffer))
{
image = BitmapSourceHelper.FromStream(memoryStream);
}
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);
}
result = expiration > DateTime.UtcNow;
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", cacheKey, ex.Message);
}
}
return result;
}
private static void SetCachedImage(string cacheKey, MemoryStream memoryStream, DateTime expiration)
{
memoryStream.Seek(0, SeekOrigin.End);
memoryStream.Write(Encoding.ASCII.GetBytes("EXPIRES:"), 0, 8);
memoryStream.Write(BitConverter.GetBytes(expiration.Ticks), 0, 8);
Cache.Set(cacheKey, memoryStream.ToArray(), new CacheItemPolicy { AbsoluteExpiration = expiration });
}
private static DateTime GetExpiration(WebHeaderCollection headers)
{
var expiration = DefaultCacheExpiration;
var cacheControl = headers["Cache-Control"];
if (cacheControl != null)
{
int maxAgeValue;
var maxAgeDirective = cacheControl
.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.FirstOrDefault(s => s.StartsWith("max-age="));
if (maxAgeDirective != null &&
int.TryParse(maxAgeDirective.Substring(8), out maxAgeValue))
{
expiration = TimeSpan.FromSeconds(maxAgeValue);
if (expiration < MinimumCacheExpiration)
{
expiration = MinimumCacheExpiration;
}
}
}
return DateTime.UtcNow.Add(expiration);
}
}
}

View file

@ -1,295 +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;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Web.Http;
using Windows.Web.Http.Filters;
namespace MapControl
{
/// <summary>
/// Loads map tile images and optionally caches them in a IImageCache.
/// </summary>
public class TileImageLoader : ITileImageLoader
{
/// <summary>
/// Default name of an IImageCache instance that is assigned to the Cache property.
/// </summary>
public const string DefaultCacheName = "TileCache";
/// <summary>
/// Default StorageFolder where an IImageCache instance may save cached data.
/// </summary>
public static readonly StorageFolder DefaultCacheFolder = ApplicationData.Current.TemporaryFolder;
/// <summary>
/// Default expiration time for cached tile images. Used when no expiration time
/// was transmitted on download. The default value is one day.
/// </summary>
public static TimeSpan DefaultCacheExpiration { get; set; }
/// <summary>
/// Minimum expiration time for cached tile images. Used when an unnecessarily small expiration time
/// was transmitted on download (e.g. Cache-Control: max-age=0). The default value is one hour.
/// </summary>
public static TimeSpan MinimumCacheExpiration { get; set; }
/// <summary>
/// The IImageCache implementation used to cache tile images. The default is null.
/// </summary>
public static Caching.IImageCache Cache;
static TileImageLoader()
{
DefaultCacheExpiration = TimeSpan.FromDays(1);
MinimumCacheExpiration = TimeSpan.FromHours(1);
}
private readonly ConcurrentStack<Tile> pendingTiles = new ConcurrentStack<Tile>();
private int taskCount;
public void LoadTiles(MapTileLayer tileLayer)
{
pendingTiles.Clear();
var tiles = tileLayer.Tiles.Where(t => t.Pending);
if (tiles.Any())
{
var tileSource = tileLayer.TileSource;
var imageTileSource = tileSource as ImageTileSource;
if (imageTileSource != null)
{
LoadTiles(tiles, imageTileSource);
}
else
{
pendingTiles.PushRange(tiles.Reverse().ToArray());
var sourceName = tileLayer.SourceName;
var maxDownloads = tileLayer.MaxParallelDownloads;
while (taskCount < Math.Min(pendingTiles.Count, maxDownloads))
{
Interlocked.Increment(ref taskCount);
Task.Run(async () =>
{
await LoadPendingTiles(tileSource, sourceName);
Interlocked.Decrement(ref taskCount);
});
}
}
}
}
private void LoadTiles(IEnumerable<Tile> tiles, ImageTileSource tileSource)
{
foreach (var tile in tiles)
{
tile.Pending = false;
try
{
var image = tileSource.LoadImage(tile.XIndex, tile.Y, tile.ZoomLevel);
if (image != null)
{
tile.SetImage(image);
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
}
}
}
private async Task LoadPendingTiles(TileSource tileSource, string sourceName)
{
Tile tile;
while (pendingTiles.TryPop(out tile))
{
tile.Pending = false;
try
{
var uri = tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel);
if (uri != null)
{
if (!uri.IsAbsoluteUri)
{
await LoadImageFromFile(tile, uri.OriginalString);
}
else if (uri.Scheme == "file")
{
await LoadImageFromFile(tile, uri.LocalPath);
}
else if (Cache == null || sourceName == null)
{
await DownloadImage(tile, uri, null);
}
else
{
var extension = Path.GetExtension(uri.LocalPath);
if (string.IsNullOrEmpty(extension) || extension == ".jpeg")
{
extension = ".jpg";
}
var cacheKey = string.Format(@"{0}\{1}\{2}\{3}{4}", sourceName, tile.ZoomLevel, tile.XIndex, tile.Y, extension);
var cacheItem = await Cache.GetAsync(cacheKey);
var loaded = false;
if (cacheItem == null || cacheItem.Expiration <= DateTime.UtcNow)
{
loaded = await DownloadImage(tile, uri, cacheKey);
}
if (!loaded && cacheItem != null && cacheItem.Buffer != null)
{
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(cacheItem.Buffer);
await stream.FlushAsync();
stream.Seek(0);
await LoadImageFromStream(tile, stream);
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message);
}
}
}
private async Task<bool> DownloadImage(Tile tile, Uri uri, string cacheKey)
{
try
{
using (var httpClient = new HttpClient(new HttpBaseProtocolFilter { AllowAutoRedirect = false }))
using (var response = await httpClient.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
string tileInfo;
if (!response.Headers.TryGetValue("X-VE-Tile-Info", out tileInfo) || tileInfo != "no-tile") // set by Bing Maps
{
await LoadImageFromHttpResponse(response, tile, cacheKey);
}
return true;
}
Debug.WriteLine("{0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase);
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", uri, ex.Message);
}
return false;
}
private async Task LoadImageFromHttpResponse(HttpResponseMessage response, Tile tile, string cacheKey)
{
using (var stream = new InMemoryRandomAccessStream())
{
using (var content = response.Content)
{
await content.WriteToStreamAsync(stream);
}
await stream.FlushAsync();
stream.Seek(0);
await LoadImageFromStream(tile, stream);
if (cacheKey != null)
{
var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
stream.Seek(0);
await stream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.None);
var expiration = DefaultCacheExpiration;
if (response.Headers.CacheControl.MaxAge.HasValue)
{
expiration = response.Headers.CacheControl.MaxAge.Value;
if (expiration < MinimumCacheExpiration)
{
expiration = MinimumCacheExpiration;
}
}
await Cache.SetAsync(cacheKey, buffer, DateTime.UtcNow.Add(expiration));
}
}
}
private async Task LoadImageFromFile(Tile tile, string path)
{
try
{
var file = await StorageFile.GetFileFromPathAsync(path);
using (var stream = await file.OpenReadAsync())
{
await LoadImageFromStream(tile, stream);
}
}
catch (Exception ex)
{
Debug.WriteLine("{0}: {1}", path, ex.Message);
}
}
private async Task LoadImageFromStream(Tile tile, IRandomAccessStream stream)
{
var tcs = new TaskCompletionSource<object>();
await tile.Image.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
{
try
{
var image = new BitmapImage();
await image.SetSourceAsync(stream);
tile.SetImage(image, true, false);
tcs.SetResult(null);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
await tcs.Task;
}
}
}

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;
using System.ComponentModel;
using System.Globalization;
namespace MapControl
{
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
{
}
}

View file

@ -2,10 +2,8 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Media.Animation;
@ -14,11 +12,6 @@ namespace MapControl
{ {
internal static class Extensions internal static class Extensions
{ {
public static IAsyncAction BeginInvoke(this CoreDispatcher dispatcher, Action action)
{
return dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(action));
}
public static Point Transform(this GeneralTransform transform, Point point) public static Point Transform(this GeneralTransform transform, Point point)
{ {
return transform.TransformPoint(point); return transform.TransformPoint(point);
@ -47,6 +40,7 @@ namespace MapControl
private static void BeginAnimation(DependencyObject obj, DependencyProperty property, Timeline animation) private static void BeginAnimation(DependencyObject obj, DependencyProperty property, Timeline animation)
{ {
string propertyName; string propertyName;
if (properties.TryGetValue(property, out propertyName)) if (properties.TryGetValue(property, out propertyName))
{ {
Storyboard.SetTargetProperty(animation, propertyName); Storyboard.SetTargetProperty(animation, propertyName);

View file

@ -0,0 +1,99 @@
// 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.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
namespace MapControl.Caching
{
public class ImageFileCache : IImageCache
{
private StorageFolder rootFolder;
public ImageFileCache(StorageFolder rootFolder)
{
if (rootFolder == null)
{
throw new ArgumentNullException("The parameter rootFolder must not be null.");
}
this.rootFolder = rootFolder;
Debug.WriteLine("Created ImageFileCache in " + rootFolder.Path);
}
public virtual async Task<ImageCacheItem> GetAsync(string key)
{
string path = null;
try
{
path = Path.Combine(key.Split('\\', '/', ':', ';'));
}
catch (Exception ex)
{
Debug.WriteLine("ImageFileCache: Invalid key {0}: {1}", key, ex.Message);
}
if (path != null)
{
var item = await rootFolder.TryGetItemAsync(path);
if (item != null && item.IsOfType(StorageItemTypes.File))
{
var file = (StorageFile)item;
//Debug.WriteLine("ImageFileCache: Reading " + file.Path);
try
{
return new ImageCacheItem
{
Buffer = await FileIO.ReadBufferAsync(file),
Expiration = (await file.Properties.GetImagePropertiesAsync()).DateTaken.UtcDateTime
};
}
catch (Exception ex)
{
Debug.WriteLine("ImageFileCache: Reading {0}: {1}", file.Path, ex.Message);
}
}
}
return null;
}
public virtual async Task SetAsync(string key, IBuffer buffer, DateTime expiration)
{
var paths = key.Split('\\', '/', ':', ';');
try
{
var folder = rootFolder;
for (int i = 0; i < paths.Length - 1; i++)
{
folder = await folder.CreateFolderAsync(paths[i], CreationCollisionOption.OpenIfExists);
}
var file = await folder.CreateFileAsync(paths[paths.Length - 1], CreationCollisionOption.ReplaceExisting);
//Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", file.Path, expiration.ToLocalTime());
await FileIO.WriteBufferAsync(file, buffer);
// Store expiration date in ImageProperties.DateTaken
var properties = await file.Properties.GetImagePropertiesAsync();
properties.DateTaken = expiration;
await properties.SavePropertiesAsync();
}
catch (Exception ex)
{
Debug.WriteLine("ImageFileCache: Writing {0}\\{1}: {2}", rootFolder.Path, string.Join("\\", paths), ex.Message);
}
}
}
}

View file

@ -2,15 +2,10 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.Foundation; using Windows.Foundation;
using Windows.UI; using Windows.UI;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl namespace MapControl
{ {

View file

@ -0,0 +1,180 @@
<?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>{951BC5D2-D653-42D9-9A91-21DC50DE0182}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl</RootNamespace>
<AssemblyName>MapControl.UWP</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.10240.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<None Include="..\..\MapControl.snk">
<Link>MapControl.snk</Link>
</None>
<None Include="project.json" />
</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="Extensions.UWP.cs" />
<Compile Include="ImageCache.UWP.cs" />
<Compile Include="ImageFileCache.UWP.cs" />
<Compile Include="Map.UWP.cs" />
<Compile Include="MapBase.UWP.cs" />
<Compile Include="MapGraticule.UWP.cs" />
<Compile Include="MapImageLayer.UWP.cs" />
<Compile Include="MapItem.UWP.cs" />
<Compile Include="MapItemsControl.UWP.cs" />
<Compile Include="MapOverlay.UWP.cs" />
<Compile Include="MapPanel.UWP.cs" />
<Compile Include="MapPath.UWP.cs" />
<Compile Include="MapPolyline.UWP.cs" />
<Compile Include="MapTileLayer.UWP.cs" />
<Compile Include="MatrixEx.UWP.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pushpin.UWP.cs" />
<Compile Include="Tile.UWP.cs" />
<Compile Include="TileImageLoader.UWP.cs" />
<EmbeddedResource Include="Properties\MapControl.UWP.rd.xml" />
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\..\MapControl.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.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>

View file

@ -3,20 +3,12 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes; using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Data;
#else
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Data;
#endif
namespace MapControl namespace MapControl
{ {

View file

@ -3,15 +3,9 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
#endif
namespace MapControl namespace MapControl
{ {
@ -19,14 +13,14 @@ namespace MapControl
{ {
protected void UpdateImage(Uri uri) protected void UpdateImage(Uri uri)
{ {
UpdateImage(new BitmapImage(uri)); UpdateImage(uri != null ? new BitmapImage(uri) : null);
} }
protected void UpdateImage(BitmapSource bitmap) protected void UpdateImage(BitmapSource bitmapSource)
{ {
SetTopImage(bitmap); SetTopImage(bitmapSource);
var bitmapImage = bitmap as BitmapImage; var bitmapImage = bitmapSource as BitmapImage;
if (bitmapImage != null) if (bitmapImage != null)
{ {
@ -41,18 +35,20 @@ namespace MapControl
private void BitmapImageOpened(object sender, RoutedEventArgs e) private void BitmapImageOpened(object sender, RoutedEventArgs e)
{ {
var bitmap = (BitmapImage)sender; var bitmapImage = (BitmapImage)sender;
bitmap.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed; bitmapImage.ImageOpened -= BitmapImageOpened;
bitmapImage.ImageFailed -= BitmapImageFailed;
SwapImages(); SwapImages();
} }
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e) private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
{ {
var bitmap = (BitmapImage)sender; var bitmapImage = (BitmapImage)sender;
bitmap.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed; bitmapImage.ImageOpened -= BitmapImageOpened;
bitmapImage.ImageFailed -= BitmapImageFailed;
((Image)Children[topImageIndex]).Source = null; ((Image)Children[topImageIndex]).Source = null;
SwapImages(); SwapImages();

View file

@ -2,11 +2,7 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
#else
using System.Windows.Controls;
#endif
namespace MapControl namespace MapControl
{ {

View file

@ -2,13 +2,8 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
#else
using System.Windows;
using System.Windows.Controls;
#endif
namespace MapControl namespace MapControl
{ {

View file

@ -2,24 +2,13 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Text; using Windows.UI.Text;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
#endif
namespace MapControl namespace MapControl
{ {
#if NETFX_CORE
class FontStyles { public const FontStyle Normal = FontStyle.Normal; }
class FontStretches { public const FontStretch Normal = FontStretch.Normal; }
#endif
public partial class MapOverlay public partial class MapOverlay
{ {
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register( public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
@ -29,10 +18,10 @@ namespace MapControl
nameof(FontFamily), typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null)); nameof(FontFamily), typeof(FontFamily), typeof(MapOverlay), new PropertyMetadata(null));
public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register( public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register(
nameof(FontStyle), typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(FontStyles.Normal)); nameof(FontStyle), typeof(FontStyle), typeof(MapOverlay), new PropertyMetadata(FontStyle.Normal));
public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register( public static readonly DependencyProperty FontStretchProperty = DependencyProperty.Register(
nameof(FontStretch), typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(FontStretches.Normal)); nameof(FontStretch), typeof(FontStretch), typeof(MapOverlay), new PropertyMetadata(FontStretch.Normal));
public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register( public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register(
nameof(FontWeight), typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(FontWeights.Normal)); nameof(FontWeight), typeof(FontWeight), typeof(MapOverlay), new PropertyMetadata(FontWeights.Normal));

View file

@ -2,13 +2,8 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl namespace MapControl
{ {

View file

@ -2,15 +2,9 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes; using Windows.UI.Xaml.Shapes;
#else
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
#endif
namespace MapControl namespace MapControl
{ {
@ -23,7 +17,7 @@ namespace MapControl
MapPanel.AddParentMapHandlers(this); MapPanel.AddParentMapHandlers(this);
} }
protected override Size MeasureOverride(Size constraint) protected override Size MeasureOverride(Size availableSize)
{ {
if (Stretch != Stretch.None) if (Stretch != Stretch.None)
{ {
@ -46,12 +40,7 @@ namespace MapControl
} }
} }
// Path.MeasureOverride in Windows Runtime sometimes returns an empty Size, return new Size();
// whereas in Silverlight it occasionally throws an ArgumentException,
// apparently because it tries to create a Size from negative width or height,
// which result from a transformed Geometry.
// In either case it seems to be sufficient to simply return a non-zero size.
return new Size(1, 1);
} }
} }
} }

View file

@ -2,14 +2,10 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System.Collections.Generic;
using System.Linq; using System.Linq;
#if NETFX_CORE
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl namespace MapControl
{ {
@ -19,11 +15,21 @@ namespace MapControl
nameof(FillRule), typeof(FillRule), typeof(MapPolyline), nameof(FillRule), typeof(FillRule), typeof(MapPolyline),
new PropertyMetadata(FillRule.EvenOdd, (o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue)); new PropertyMetadata(FillRule.EvenOdd, (o, e) => ((PathGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
public MapPolyline() public MapPolyline()
{ {
Data = new PathGeometry(); Data = new PathGeometry();
} }
/// <summary>
/// Gets or sets the locations that define the polyline points.
/// </summary>
public IEnumerable<Location> Locations
{
get { return (IEnumerable<Location>)GetValue(LocationsProperty); }
set { SetValue(LocationsProperty, value); }
}
protected override void UpdateData() protected override void UpdateData()
{ {
var geometry = (PathGeometry)Data; var geometry = (PathGeometry)Data;

View file

@ -2,8 +2,11 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using Windows.UI.Xaml.Markup;
namespace MapControl namespace MapControl
{ {
[ContentProperty(Name = "TileSource")]
public partial class MapTileLayer public partial class MapTileLayer
{ {
partial void Initialize() partial void Initialize()

View file

@ -0,0 +1,87 @@
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
// © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using Windows.UI.Xaml.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(
scaleX, 0d, 0d, scaleY,
scaleX * translation1X,
scaleY * translation1Y);
if (rotationAngle != 0d)
{
rotationAngle = (rotationAngle % 360d) / 180d * Math.PI;
var cos = Math.Cos(rotationAngle);
var sin = Math.Sin(rotationAngle);
matrix = new Matrix(
matrix.M11 * cos - matrix.M12 * sin,
matrix.M11 * sin + matrix.M12 * cos,
matrix.M21 * cos - matrix.M22 * sin,
matrix.M21 * sin + matrix.M22 * cos,
cos * matrix.OffsetX - sin * matrix.OffsetY,
sin * matrix.OffsetX + cos * matrix.OffsetY);
}
matrix.OffsetX += translation2X;
matrix.OffsetY += translation2Y;
return matrix;
}
public static Matrix TranslateScaleRotateTranslate_(
double translation1X, double translation1Y,
double scaleX, double scaleY, double rotationAngle,
double translation2X, double translation2Y)
{
var m11 = scaleX;
var m12 = 0d;
var m21 = 0d;
var m22 = scaleY;
var offsetX = scaleX * translation1X;
var offsetY = scaleY * translation1Y;
if (rotationAngle != 0d)
{
rotationAngle = (rotationAngle % 360d) / 180d * Math.PI;
var cos = Math.Cos(rotationAngle);
var sin = Math.Sin(rotationAngle);
var _m11 = m11;
var _m12 = m12;
var _m21 = m21;
var _m22 = m22;
var _offsetX = offsetX;
var _offsetY = offsetY;
m11 = _m11 * cos - _m12 * sin;
m12 = _m11 * sin + _m12 * cos;
m21 = _m21 * cos - _m22 * sin;
m22 = _m21 * sin + _m22 * cos;
offsetX = cos * _offsetX - sin * _offsetY;
offsetY = sin * _offsetX + cos * _offsetY;
}
offsetX += translation2X;
offsetY += translation2Y;
return new Matrix(m11, m12, m21, m22, offsetX, offsetY);
}
}
}

View file

@ -1,14 +1,14 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
[assembly: AssemblyTitle("XAML Map Control (WinRT)")] [assembly: AssemblyTitle("XAML Map Control for UWP")]
[assembly: AssemblyDescription("XAML Map Control Library for Windows Runtime")] [assembly: AssemblyDescription("XAML Map Control Library for UWP")]
[assembly: AssemblyProduct("XAML Map Control")] [assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.4.1")] [assembly: AssemblyVersion("4.0.0")]
[assembly: AssemblyFileVersion("3.4.1")] [assembly: AssemblyFileVersion("4.0.0")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="MapControl.UWP">
</Library>
</Directives>

View file

@ -2,11 +2,7 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
#if NETFX_CORE
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
#else
using System.Windows.Controls;
#endif
namespace MapControl namespace MapControl
{ {

View file

@ -3,36 +3,28 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System; using System;
#if NETFX_CORE
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
#endif
namespace MapControl namespace MapControl
{ {
public partial class Tile public partial class Tile
{ {
public void SetImage(ImageSource image, bool fadeIn = true, bool isDownloading = true) public void SetImage(ImageSource imageSource, bool fadeIn = true)
{ {
Pending = false; Pending = false;
if (fadeIn && FadeDuration > TimeSpan.Zero) if (fadeIn && FadeDuration > TimeSpan.Zero)
{ {
BitmapImage bitmap; var bitmapImage = imageSource as BitmapImage;
if (isDownloading && (bitmap = image as BitmapImage) != null) if (bitmapImage != null && bitmapImage.UriSource != null)
{ {
bitmap.ImageOpened += BitmapImageOpened; bitmapImage.ImageOpened += BitmapImageOpened;
bitmap.ImageFailed += BitmapImageFailed; bitmapImage.ImageFailed += BitmapImageFailed;
} }
else else
{ {
@ -45,15 +37,15 @@ namespace MapControl
Image.Opacity = 1d; Image.Opacity = 1d;
} }
Image.Source = image; Image.Source = imageSource;
} }
private void BitmapImageOpened(object sender, RoutedEventArgs e) private void BitmapImageOpened(object sender, RoutedEventArgs e)
{ {
var bitmap = (BitmapImage)sender; var bitmapImage = (BitmapImage)sender;
bitmap.ImageOpened -= BitmapImageOpened; bitmapImage.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed; bitmapImage.ImageFailed -= BitmapImageFailed;
Image.BeginAnimation(UIElement.OpacityProperty, Image.BeginAnimation(UIElement.OpacityProperty,
new DoubleAnimation { From = 0d, To = 1d, Duration = FadeDuration }); new DoubleAnimation { From = 0d, To = 1d, Duration = FadeDuration });
@ -61,10 +53,10 @@ namespace MapControl
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e) private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
{ {
var bitmap = (BitmapImage)sender; var bitmapImage = (BitmapImage)sender;
bitmap.ImageOpened -= BitmapImageOpened; bitmapImage.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed; bitmapImage.ImageFailed -= BitmapImageFailed;
Image.Source = null; Image.Source = null;
} }

View file

@ -0,0 +1,114 @@
// 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.Diagnostics;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml.Media.Imaging;
using Windows.Web.Http;
namespace MapControl
{
public partial class TileImageLoader : ITileImageLoader
{
/// <summary>
/// Default StorageFolder where an IImageCache instance may save cached data.
/// </summary>
public static readonly StorageFolder DefaultCacheFolder = ApplicationData.Current.TemporaryFolder;
/// <summary>
/// The IImageCache implementation used to cache tile images. The default is null.
/// </summary>
public static Caching.IImageCache Cache { get; set; }
private async Task LoadTileImageAsync(Tile tile, Uri uri, string cacheKey)
{
var cacheItem = await Cache.GetAsync(cacheKey);
var buffer = cacheItem?.Buffer;
var loaded = false;
//if (buffer != null)
//{
// Debug.WriteLine("TileImageLoader: {0}: expire{1} {2}", cacheKey, cacheItem.Expiration < DateTime.UtcNow ? "d" : "s", cacheItem.Expiration);
//}
if (buffer == null || cacheItem.Expiration < DateTime.UtcNow)
{
loaded = await DownloadTileImageAsync(tile, uri, cacheKey);
}
if (!loaded && buffer != null) // keep expired image if download failed
{
await SetTileImageAsync(tile, buffer);
}
}
private async Task<bool> DownloadTileImageAsync(Tile tile, Uri uri, string cacheKey)
{
try
{
using (var response = await HttpClient.GetAsync(uri))
{
if (response.IsSuccessStatusCode)
{
string tileInfo;
if (!response.Headers.TryGetValue(bingMapsTileInfo, out tileInfo) ||
tileInfo != bingMapsNoTile)
{
var buffer = await response.Content.ReadAsBufferAsync();
await SetTileImageAsync(tile, buffer); // create BitmapImage in UI thread before caching
await Cache.SetAsync(cacheKey, buffer, 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, IBuffer buffer)
{
var tcs = new TaskCompletionSource<object>();
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(buffer);
await stream.FlushAsync(); // necessary?
stream.Seek(0);
await tile.Image.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
try
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(stream);
tile.SetImage(bitmapImage);
tcs.SetResult(null);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
}
await tcs.Task;
}
}
}

View file

@ -0,0 +1,16 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.1.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

View file

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -20,52 +19,28 @@ namespace MapControl.Caching
/// </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, 0x0D, 0x0A, 0x1A, 0x0A }),
new Tuple<string, byte[]>(".jpg", new byte[] { 0xFF, 0xD8, 0xFF }),
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, 0x2A, 0x00 }),
new Tuple<string, byte[]>(".tif", new byte[] { 0x4D, 0x4D, 0x00, 0x2A }),
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);
private readonly MemoryCache memoryCache = MemoryCache.Default; private readonly MemoryCache memoryCache = MemoryCache.Default;
private readonly string name;
private readonly string rootFolder; private readonly string rootFolder;
public ImageFileCache(string name, NameValueCollection config) public ImageFileCache(string rootFolder)
: this(name, config["folder"])
{ {
if (string.IsNullOrEmpty(rootFolder))
{
throw new ArgumentException("The parameter rootFolder must not be null or empty.");
} }
public ImageFileCache(string name, string folder) this.rootFolder = rootFolder;
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("The parameter name must not be null or empty.");
}
if (string.IsNullOrEmpty(folder))
{
throw new ArgumentException("The parameter folder must not be null or empty.");
}
this.name = name;
rootFolder = Path.Combine(folder, name);
Directory.CreateDirectory(rootFolder);
Debug.WriteLine("Created ImageFileCache in " + rootFolder); Debug.WriteLine("Created ImageFileCache in " + rootFolder);
} }
public override string Name public override string Name
{ {
get { return name; } get { return string.Empty; }
} }
public override DefaultCacheCapabilities DefaultCacheCapabilities public override DefaultCacheCapabilities DefaultCacheCapabilities
@ -178,9 +153,10 @@ namespace MapControl.Caching
memoryCache.Set(key, buffer, policy); memoryCache.Set(key, buffer, policy);
var path = Path.Combine(rootFolder, key) var path = GetPath(key);
+ imageFileTypes.First(t => t.Item2.SequenceEqual(buffer.Take(t.Item2.Length))).Item1;
if (path != null)
{
try try
{ {
//Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", path, policy.AbsoluteExpiration.DateTime.ToLocalTime()); //Debug.WriteLine("ImageFileCache: Writing {0}, Expires {1}", path, policy.AbsoluteExpiration.DateTime.ToLocalTime());
@ -196,6 +172,7 @@ namespace MapControl.Caching
Debug.WriteLine("ImageFileCache: Failed writing {0}: {1}", path, ex.Message); Debug.WriteLine("ImageFileCache: Failed writing {0}: {1}", path, ex.Message);
} }
} }
}
public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null) public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
{ {
@ -263,21 +240,14 @@ namespace MapControl.Caching
private string FindFile(string key) private string FindFile(string key)
{ {
var path = Path.Combine(rootFolder, key); var path = GetPath(key);
try try
{ {
if (!string.IsNullOrEmpty(Path.GetExtension(path))) if (path != null && File.Exists(path))
{ {
return path; return path;
} }
string folderName = Path.GetDirectoryName(path);
if (Directory.Exists(folderName))
{
return Directory.EnumerateFiles(folderName, Path.GetFileName(path) + ".*").FirstOrDefault();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -286,5 +256,19 @@ namespace MapControl.Caching
return null; 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;
}
} }
} }

View 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>

View 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();
}
}
}

View file

@ -31,10 +31,9 @@ namespace MapControl
get { return Data; } get { return Data; }
} }
protected override Size MeasureOverride(Size constraint) protected override Size MeasureOverride(Size availableSize)
{ {
// Shape.MeasureOverride sometimes returns an empty Size. return new Size();
return new Size(1, 1);
} }
private static void DataPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) private static void DataPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)

View file

@ -2,6 +2,8 @@
// © 2017 Clemens Fischer // © 2017 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
@ -10,15 +12,26 @@ namespace MapControl
{ {
public partial class MapPolyline public partial class MapPolyline
{ {
public static readonly DependencyProperty FillRuleProperty = StreamGeometry.FillRuleProperty.AddOwner( public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register(
typeof(MapPolyline), nameof(FillRule), typeof(FillRule), typeof(MapPolyline), new FrameworkPropertyMetadata(
new FrameworkPropertyMetadata((o, e) => ((StreamGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue)); FillRule.EvenOdd, FrameworkPropertyMetadataOptions.AffectsRender,
(o, e) => ((StreamGeometry)((MapPolyline)o).Data).FillRule = (FillRule)e.NewValue));
public MapPolyline() public MapPolyline()
{ {
Data = new StreamGeometry(); 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() protected override void UpdateData()
{ {
var geometry = (StreamGeometry)Data; var geometry = (StreamGeometry)Data;

View file

@ -3,9 +3,11 @@
// Licensed under the Microsoft Public License (Ms-PL) // Licensed under the Microsoft Public License (Ms-PL)
using System.Windows; using System.Windows;
using System.Windows.Markup;
namespace MapControl namespace MapControl
{ {
[ContentProperty("TileSource")]
public partial class MapTileLayer public partial class MapTileLayer
{ {
static MapTileLayer() static MapTileLayer()

View file

@ -16,7 +16,7 @@ namespace MapControl
double scaleX, double scaleY, double rotationAngle, double scaleX, double scaleY, double rotationAngle,
double translation2X, double translation2Y) double translation2X, double translation2Y)
{ {
var matrix = new Matrix(1d, 0d, 0d, 1d, -translation1X, -translation1Y); var matrix = new Matrix(1d, 0d, 0d, 1d, translation1X, translation1Y);
matrix.Scale(scaleX, scaleY); matrix.Scale(scaleX, scaleY);
matrix.Rotate(rotationAngle); matrix.Rotate(rotationAngle);
matrix.Translate(translation2X, translation2Y); matrix.Translate(translation2X, translation2Y);

View file

@ -2,20 +2,15 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows; using System.Windows;
#if SILVERLIGHT [assembly: AssemblyTitle("XAML Map Control for WPF")]
[assembly: AssemblyTitle("XAML Map Control (Silverlight)")]
[assembly: AssemblyDescription("XAML Map Control Library for Silverlight")]
#else
[assembly: AssemblyTitle("XAML Map Control (WPF)")]
[assembly: AssemblyDescription("XAML Map Control Library for WPF")] [assembly: AssemblyDescription("XAML Map Control Library for WPF")]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
#endif
[assembly: AssemblyProduct("XAML Map Control")] [assembly: AssemblyProduct("XAML Map Control")]
[assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("3.4.1")] [assembly: AssemblyVersion("4.0.0")]
[assembly: AssemblyFileVersion("3.4.1")] [assembly: AssemblyFileVersion("4.0.0")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]

Some files were not shown because too many files have changed in this diff Show more