Version 2.3.0:

- Added BingMapsTileLayer
- Added TileLayer.DescriptionInlines property
- Added global Settings class
- Added Phone Silverlight 8.1 build target
- Use expiration time of downloaded images for caching
This commit is contained in:
ClemensF 2014-10-19 21:50:23 +02:00
parent 8917e1d4cb
commit 91ff46c506
58 changed files with 1225 additions and 491 deletions

View file

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

View file

@ -128,12 +128,18 @@ namespace Caching
if (path != null)
{
var creationTime = File.GetLastWriteTimeUtc(path).ToBinary();
var expirationTime = File.GetLastAccessTimeUtc(path);
var creationTime = File.GetLastWriteTimeUtc(path);
if (expirationTime < creationTime)
{
expirationTime = creationTime;
}
using (var fileStream = new FileStream(path, FileMode.Open))
using (var memoryStream = new MemoryStream((int)(fileStream.Length + 8)))
{
memoryStream.Write(BitConverter.GetBytes(creationTime), 0, 8);
memoryStream.Write(BitConverter.GetBytes(expirationTime.ToBinary()), 0, 8);
fileStream.CopyTo(memoryStream);
value = memoryStream.GetBuffer();
}
@ -150,6 +156,7 @@ namespace Caching
public override CacheItem GetCacheItem(string key, string regionName = null)
{
var value = Get(key, regionName);
return value != null ? new CacheItem(key, value) : null;
}
@ -197,6 +204,9 @@ namespace Caching
fileStream.Write(buffer, 8, buffer.Length - 8);
}
var expirationTime = DateTime.FromBinary(BitConverter.ToInt64(buffer, 0));
File.SetLastAccessTimeUtc(path, expirationTime);
var fileSecurity = File.GetAccessControl(path);
fileSecurity.AddAccessRule(fullControlRule);
File.SetAccessControl(path, fileSecurity);
@ -220,14 +230,18 @@ namespace Caching
public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
{
var oldValue = Get(key, regionName);
Set(key, value, policy);
return oldValue;
}
public override CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
{
var oldItem = GetCacheItem(item.Key, item.RegionName);
Set(item, policy);
return oldItem;
}

View file

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

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache", "Caching\FileDbCache\FileDbCache.csproj", "{EF44F661-B98A-4676-927F-85D138F82300}"
EndProject
@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilverlightApplication.Web"
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}") = "MapControl.Silverlight", "MapControl\MapControl.Silverlight.csproj", "{EB133B78-DEFF-416A-8F0C-89E54D766576}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StoreApplication", "SampleApps\StoreApplication\StoreApplication.csproj", "{747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.WinRT", "MapControl\WinRT\MapControl.WinRT.csproj", "{63CEFDF7-5170-43B6-86F8-5C4A383A1615}"
@ -23,6 +21,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfApplication", "SampleApp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneApplication", "SampleApps\PhoneApplication\PhoneApplication.csproj", "{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.Silverlight", "MapControl\MapControl.Silverlight.csproj", "{EB133B78-DEFF-416A-8F0C-89E54D766576}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.PhoneSilverlight", "MapControl\MapControl.PhoneSilverlight.csproj", "{3499D618-2846-4FCE-A418-7D211FDBDCB3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -49,10 +51,6 @@ Global
{226F3575-B683-446D-A2F0-181291DC8787}.Debug|Any CPU.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
{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}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.Build.0 = Release|Any CPU
{747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{747A3F84-E11F-4EC8-9463-98BBB1E0D0A4}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
@ -73,6 +71,14 @@ Global
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.Build.0 = Release|Any CPU
{8D0A57DF-FABF-4AEE-8768-9C18B2B43CA9}.Release|Any CPU.Deploy.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}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB133B78-DEFF-416A-8F0C-89E54D766576}.Release|Any CPU.Build.0 = Release|Any CPU
{3499D618-2846-4FCE-A418-7D211FDBDCB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3499D618-2846-4FCE-A418-7D211FDBDCB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3499D618-2846-4FCE-A418-7D211FDBDCB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3499D618-2846-4FCE-A418-7D211FDBDCB3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -0,0 +1,153 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 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 WINDOWS_RUNTIME
using Windows.UI.Xaml;
#else
using System.Windows;
#endif
namespace MapControl
{
public class BingMapsTileLayer : TileLayer
{
public enum MapMode
{
Road, Aerial, AerialWithLabels
}
public BingMapsTileLayer()
{
MinZoomLevel = 1;
MaxZoomLevel = 21;
Loaded += OnLoaded;
}
public static string ApiKey { get; set; }
public MapMode Mode { get; set; }
public string Culture { get; set; }
private void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
if (string.IsNullOrWhiteSpace(ApiKey))
{
throw new InvalidOperationException("A Bing Maps API Key must be assigned to the ApiKey property.");
}
var uri = string.Format("http://dev.virtualearth.net/REST/V1/Imagery/Metadata/{0}?output=xml&key={1}", Mode, ApiKey);
var request = HttpWebRequest.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 responseStream = response.GetResponseStream())
using (var xmlReader = XmlReader.Create(responseStream))
{
ReadImageryMetadataResponse(xmlReader);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private void ReadImageryMetadataResponse(XmlReader xmlReader)
{
string imageUrl = null;
string[] imageUrlSubdomains = null;
int? zoomMin = null;
int? zoomMax = null;
do
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
switch (xmlReader.Name)
{
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 (imageUrl != null && imageUrlSubdomains != null && imageUrlSubdomains.Length > 0)
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (string.IsNullOrWhiteSpace(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;
}
}));
}
}
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

@ -0,0 +1,39 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
namespace MapControl
{
internal class BingMapsTileSource : TileSource
{
private string[] subdomains;
public BingMapsTileSource(string uriFormat, string[] subdomains)
: base(uriFormat)
{
this.subdomains = subdomains;
}
public override Uri GetUri(int x, int y, int zoomLevel)
{
if (zoomLevel < 1)
{
return null;
}
var subdomain = subdomains[(x + y) % subdomains.Length];
var quadkey = new char[zoomLevel];
for (var z = zoomLevel - 1; z >= 0; z--, x /= 2, y /= 2)
{
quadkey[z] = (char)('0' + 2 * (y % 2) + (x % 2));
}
return new Uri(UriFormat.
Replace("{subdomain}", subdomain).
Replace("{quadkey}", new string(quadkey)));
}
}
}

View file

@ -13,10 +13,6 @@ namespace MapControl
{
internal static partial class Extensions
{
public static void Freeze(this object freezable)
{
}
public static Matrix Translate(this Matrix matrix, double offsetX, double offsetY)
{
matrix.OffsetX += offsetX;

View file

@ -2,7 +2,9 @@
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
@ -11,6 +13,11 @@ namespace MapControl
{
internal static partial class Extensions
{
public static void BeginInvoke(this CoreDispatcher dispatcher, Action action)
{
var asyncAction = dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(action));
}
public static Point Transform(this GeneralTransform transform, Point point)
{
return transform.TransformPoint(point);

View file

@ -19,7 +19,7 @@ namespace MapControl
if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
{
throw new ArgumentException(string.Format("{0}: no GlyphTypeface found", typeface.FontFamily));
throw new ArgumentException(string.Format("{0}: No GlyphTypeface found", typeface.FontFamily));
}
var glyphIndices = new ushort[text.Length];

View file

@ -0,0 +1,60 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
#if WINDOWS_RUNTIME
using Windows.UI.Xaml.Documents;
#else
using System.Windows.Documents;
#endif
namespace MapControl
{
public static class HyperlinkText
{
private static Regex regex = new Regex(@"\[([^\]]+)\]\(([^\)]+)\)");
/// <summary>
/// Converts text containing hyperlinks in markdown syntax [text](url)
/// to a collection of Run and Hyperlink inlines.
/// </summary>
public static ICollection<Inline> ToInlines(this string text)
{
var inlines = new List<Inline>();
while (!string.IsNullOrEmpty(text))
{
var match = regex.Match(text);
Uri uri;
if (match.Success &&
match.Groups.Count == 3 &&
Uri.TryCreate(match.Groups[2].Value, UriKind.Absolute, out uri))
{
inlines.Add(new Run { Text = text.Substring(0, match.Index) });
text = text.Substring(match.Index + match.Length);
var link = new Hyperlink { NavigateUri = uri };
link.Inlines.Add(new Run { Text = match.Groups[1].Value });
#if SILVERLIGHT
link.TargetName = "_blank";
#elif !WINDOWS_RUNTIME
link.ToolTip = uri.ToString();
link.RequestNavigate += (s, e) => System.Diagnostics.Process.Start(e.Uri.ToString());
#endif
inlines.Add(link);
}
else
{
inlines.Add(new Run { Text = text });
text = null;
}
}
return inlines;
}
}
}

View file

@ -4,7 +4,7 @@
namespace MapControl
{
public struct Int32Rect
internal struct Int32Rect
{
public Int32Rect(int x, int y, int width, int height)
: this()

View file

@ -28,9 +28,6 @@ namespace MapControl
{
private const double MaximumZoomLevel = 22d;
public static TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.5);
public static EasingFunctionBase AnimationEasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut };
public static readonly DependencyProperty TileLayersProperty = DependencyProperty.Register(
"TileLayers", typeof(TileLayerCollection), typeof(MapBase), new PropertyMetadata(null,
(o, e) => ((MapBase)o).TileLayersPropertyChanged((TileLayerCollection)e.OldValue, (TileLayerCollection)e.NewValue)));
@ -74,7 +71,7 @@ namespace MapControl
SetParentMap();
TileLayers = new TileLayerCollection();
InternalChildren.Add(tileContainer);
Children.Add(tileContainer);
Initialize();
Loaded += OnLoaded;
@ -578,8 +575,8 @@ namespace MapControl
{
From = MapTransform.Transform(Center),
To = MapTransform.Transform(targetCenter, Center.Longitude),
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
Duration = Settings.MapAnimationDuration,
EasingFunction = Settings.MapAnimationEasingFunction,
FillBehavior = FillBehavior.HoldEnd
};
@ -683,8 +680,8 @@ namespace MapControl
zoomLevelAnimation = new DoubleAnimation
{
To = targetZoomLevel,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
Duration = Settings.MapAnimationDuration,
EasingFunction = Settings.MapAnimationEasingFunction,
FillBehavior = FillBehavior.HoldEnd
};
@ -758,8 +755,8 @@ namespace MapControl
headingAnimation = new DoubleAnimation
{
By = delta,
Duration = AnimationDuration,
EasingFunction = AnimationEasingFunction,
Duration = Settings.MapAnimationDuration,
EasingFunction = Settings.MapAnimationEasingFunction,
FillBehavior = FillBehavior.HoldEnd
};

View file

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{3499D618-2846-4FCE-A418-7D211FDBDCB3}</ProjectGuid>
<ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MapControl</RootNamespace>
<AssemblyName>MapControl.PhoneSilverlight</AssemblyName>
<TargetFrameworkIdentifier>WindowsPhone</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Bin\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<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;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Bin\x86\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Bin\x86\Release</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Bin\ARM\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Bin\ARM\Release</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="BingMapsTileLayer.cs" />
<Compile Include="BingMapsTileSource.cs" />
<Compile Include="Extensions.Silverlight.cs" />
<Compile Include="Extensions.Silverlight.WinRT.cs" />
<Compile Include="HyperlinkText.cs" />
<Compile Include="ImageTileSource.Silverlight.WinRT.cs" />
<Compile Include="IMapElement.cs" />
<Compile Include="Int32Rect.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="MapGraticule.cs" />
<Compile Include="MapGraticule.Silverlight.WinRT.cs" />
<Compile Include="MapImage.cs" />
<Compile Include="MapImageLayer.cs" />
<Compile Include="MapImageLayer.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="MapRectangle.cs" />
<Compile Include="MapRectangle.Silverlight.WinRT.cs" />
<Compile Include="MapTransform.cs" />
<Compile Include="MercatorTransform.cs" />
<Compile Include="PanelBase.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pushpin.Silverlight.WinRT.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.Silverlight.WinRT.cs" />
<Compile Include="TileContainer.cs" />
<Compile Include="TileContainer.Silverlight.WinRT.cs" />
<Compile Include="TileImageLoader.Silverlight.cs" />
<Compile Include="TileLayer.cs" />
<Compile Include="TileLayerCollection.cs" />
<Compile Include="TileSource.cs" />
<Compile Include="TileSourceConverter.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
<ProjectExtensions />
<!-- 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,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{C089C8C0-30E0-4E22-80C0-CE093F111A43}">
<SilverlightMobileCSProjectFlavor>
<FullDeploy>True</FullDeploy>
<DebuggerType>Managed</DebuggerType>
<DebuggerAgentType>Managed</DebuggerAgentType>
<Tombstone>False</Tombstone>
</SilverlightMobileCSProjectFlavor>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View file

@ -65,10 +65,14 @@
<HintPath>$(TargetFrameworkDirectory)System.Core.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BingMapsTileLayer.cs" />
<Compile Include="BingMapsTileSource.cs" />
<Compile Include="Extensions.Silverlight.cs" />
<Compile Include="Extensions.Silverlight.WinRT.cs" />
<Compile Include="HyperlinkText.cs" />
<Compile Include="ImageTileSource.Silverlight.WinRT.cs">
<SubType>Code</SubType>
</Compile>
@ -97,11 +101,13 @@
<Compile Include="MapPolyline.cs" />
<Compile Include="MapPolyline.Silverlight.WinRT.cs" />
<Compile Include="MapRectangle.cs" />
<Compile Include="MapRectangle.Silverlight.WinRT.cs" />
<Compile Include="MapTransform.cs" />
<Compile Include="MercatorTransform.cs" />
<Compile Include="PanelBase.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pushpin.Silverlight.WinRT.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.Silverlight.WinRT.cs" />
<Compile Include="TileContainer.cs" />

View file

@ -48,10 +48,14 @@
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Xaml" />
<Reference Include="System.XML" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="BingMapsTileLayer.cs" />
<Compile Include="BingMapsTileSource.cs" />
<Compile Include="GlyphRunText.cs" />
<Compile Include="HyperlinkText.cs" />
<Compile Include="ImageTileSource.WPF.cs" />
<Compile Include="IMapElement.cs" />
<Compile Include="Location.cs" />
@ -72,6 +76,7 @@
<Compile Include="MapOverlay.WPF.cs" />
<Compile Include="MapPanel.cs" />
<Compile Include="MapPanel.WPF.cs" />
<Compile Include="MapRectangle.WPF.cs" />
<Compile Include="PanelBase.cs" />
<Compile Include="MapPath.cs" />
<Compile Include="MapPath.WPF.cs" />
@ -83,6 +88,7 @@
<Compile Include="MercatorTransform.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pushpin.WPF.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Tile.WPF.cs" />
<Compile Include="TileContainer.cs" />

View file

@ -29,16 +29,10 @@ namespace MapControl
private void SourceChanged(ImageSource image)
{
var transform = new MatrixTransform
{
Matrix = new Matrix(1d, 0d, 0d, -1d, 0d, 1d)
};
transform.Freeze();
Fill = new ImageBrush
{
ImageSource = image,
RelativeTransform = transform
RelativeTransform = FillTransform
};
}
}

View file

@ -8,16 +8,13 @@ using Windows.UI.Xaml.Media.Imaging;
#else
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
#endif
namespace MapControl
{
public partial class MapImageLayer
{
private readonly DispatcherTimer updateTimer = new DispatcherTimer();
private void AddDownloadEventHandlers(BitmapSource bitmap)
private void ImageUpdated(BitmapSource bitmap)
{
var bitmapImage = bitmap as BitmapImage;
@ -35,7 +32,6 @@ namespace MapControl
private void BitmapImageOpened(object sender, RoutedEventArgs e)
{
var bitmap = (BitmapImage)sender;
bitmap.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed;
@ -45,11 +41,12 @@ namespace MapControl
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
{
var bitmap = (BitmapImage)sender;
bitmap.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed;
((MapImage)Children[currentImageIndex]).Source = null;
var mapImage = (MapImage)Children[currentImageIndex];
mapImage.Source = null;
BlendImages();
}
}

View file

@ -5,17 +5,14 @@
using System;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace MapControl
{
public partial class MapImageLayer
{
private readonly DispatcherTimer updateTimer = new DispatcherTimer(DispatcherPriority.Background);
private void AddDownloadEventHandlers(BitmapSource bitmap)
private void ImageUpdated(BitmapSource bitmap)
{
if (bitmap.IsDownloading)
if (bitmap != null && !bitmap.IsFrozen && bitmap.IsDownloading)
{
bitmap.DownloadCompleted += BitmapDownloadCompleted;
bitmap.DownloadFailed += BitmapDownloadFailed;
@ -29,7 +26,6 @@ namespace MapControl
private void BitmapDownloadCompleted(object sender, EventArgs e)
{
var bitmap = (BitmapSource)sender;
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
bitmap.DownloadFailed -= BitmapDownloadFailed;
@ -39,11 +35,12 @@ namespace MapControl
private void BitmapDownloadFailed(object sender, ExceptionEventArgs e)
{
var bitmap = (BitmapSource)sender;
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
bitmap.DownloadFailed -= BitmapDownloadFailed;
((MapImage)Children[currentImageIndex]).Source = null;
var mapImage = (MapImage)Children[currentImageIndex];
mapImage.Source = null;
BlendImages();
}
}

View file

@ -13,14 +13,14 @@ using Windows.UI.Xaml.Media.Animation;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
#endif
namespace MapControl
{
/// <summary>
/// Map image overlay. Fills the entire viewport with a map image from a web request,
/// for example from a Web Map Service (WMS).
/// The image request Uri is specified by the UriFormat property.
/// Map image overlay. Fills the entire viewport with map images provided by a web service,
/// e.g. a Web Map Service (WMS). The image request Uri is specified by the UriFormat property.
/// </summary>
public partial class MapImageLayer : MapPanel
{
@ -31,6 +31,7 @@ namespace MapControl
public static readonly DependencyProperty RelativeImageSizeProperty = DependencyProperty.Register(
"RelativeImageSize", typeof(double), typeof(MapImageLayer), new PropertyMetadata(1d));
private readonly DispatcherTimer updateTimer;
private int currentImageIndex;
private bool updateInProgress;
@ -39,15 +40,15 @@ namespace MapControl
Children.Add(new MapImage { Opacity = 0d });
Children.Add(new MapImage { Opacity = 0d });
updateTimer.Interval = TileContainer.UpdateInterval;
updateTimer = new DispatcherTimer { Interval = Settings.TileUpdateInterval };
updateTimer.Tick += (s, e) => UpdateImage();
}
/// <summary>
/// The format string of the image request Uri. The format must contain {X} and {Y}
/// format specifiers for the map width and height in pixels, and either
/// {w},{s},{e},{n} for the bounding box in lat/lon (like for example EPSG:4326) or
/// {W},{S},{E},{N} for the bounding box in meters (like for example EPSG:3857).
/// The format string of the image request Uri. The format must contain
/// {X} and {Y} format specifiers for the map width and height in pixels and either
/// {w},{s},{e},{n} for the bounding box in lat/lon (like EPSG:4326) or
/// {W},{S},{E},{N} for the bounding box in meters (like EPSG:3857).
/// </summary>
public string UriFormat
{
@ -74,10 +75,46 @@ namespace MapControl
updateTimer.Start();
}
protected virtual BitmapSource GetBitmap(double west, double east, double south, double north, int width, int height)
protected void UpdateImage()
{
BitmapImage image = null;
updateTimer.Stop();
if (updateInProgress)
{
updateTimer.Start(); // update image on next timer tick
}
else if (ParentMap != null && RenderSize.Width > 0 && RenderSize.Height > 0)
{
updateInProgress = true;
var relativeSize = Math.Max(RelativeImageSize, 1d);
var width = RenderSize.Width * relativeSize;
var height = RenderSize.Height * relativeSize;
var dx = (RenderSize.Width - width) / 2d;
var dy = (RenderSize.Height - height) / 2d;
var loc1 = ParentMap.ViewportPointToLocation(new Point(dx, dy));
var loc2 = ParentMap.ViewportPointToLocation(new Point(dx + width, dy));
var loc3 = ParentMap.ViewportPointToLocation(new Point(dx, dy + height));
var loc4 = ParentMap.ViewportPointToLocation(new Point(dx + width, dy + height));
var west = Math.Min(loc1.Longitude, Math.Min(loc2.Longitude, Math.Min(loc3.Longitude, loc4.Longitude)));
var east = Math.Max(loc1.Longitude, Math.Max(loc2.Longitude, Math.Max(loc3.Longitude, loc4.Longitude)));
var south = Math.Min(loc1.Latitude, Math.Min(loc2.Latitude, Math.Min(loc3.Latitude, loc4.Latitude)));
var north = Math.Max(loc1.Latitude, Math.Max(loc2.Latitude, Math.Max(loc3.Latitude, loc4.Latitude)));
var p1 = ParentMap.MapTransform.Transform(new Location(south, west));
var p2 = ParentMap.MapTransform.Transform(new Location(north, east));
width = Math.Round((p2.X - p1.X) * ParentMap.ViewportScale);
height = Math.Round((p2.Y - p1.Y) * ParentMap.ViewportScale);
UpdateImage(west, east, south, north, (int)width, (int)height);
}
}
protected virtual void UpdateImage(double west, double east, double south, double north, int width, int height)
{
if (UriFormat != null && width > 0 && height > 0)
{
var uri = UriFormat.Replace("{X}", width.ToString()).Replace("{Y}", height.ToString());
@ -102,98 +139,56 @@ namespace MapControl
Replace("{n}", north.ToString(CultureInfo.InvariantCulture));
}
image = new BitmapImage(new Uri(uri));
}
return image;
}
protected void UpdateImage()
{
if (updateInProgress)
{
updateTimer.Start(); // update image on next timer tick
UpdateImage(west, east, south, north, new Uri(uri));
}
else
{
updateTimer.Stop();
if (ParentMap != null && RenderSize.Width > 0 && RenderSize.Height > 0)
{
updateInProgress = true;
var relativeSize = Math.Max(RelativeImageSize, 1d);
var width = RenderSize.Width * relativeSize;
var height = RenderSize.Height * relativeSize;
var dx = (RenderSize.Width - width) / 2d;
var dy = (RenderSize.Height - height) / 2d;
var loc1 = ParentMap.ViewportPointToLocation(new Point(dx, dy));
var loc2 = ParentMap.ViewportPointToLocation(new Point(dx + width, dy));
var loc3 = ParentMap.ViewportPointToLocation(new Point(dx, dy + height));
var loc4 = ParentMap.ViewportPointToLocation(new Point(dx + width, dy + height));
var west = Math.Min(loc1.Longitude, Math.Min(loc2.Longitude, Math.Min(loc3.Longitude, loc4.Longitude)));
var east = Math.Max(loc1.Longitude, Math.Max(loc2.Longitude, Math.Max(loc3.Longitude, loc4.Longitude)));
var south = Math.Min(loc1.Latitude, Math.Min(loc2.Latitude, Math.Min(loc3.Latitude, loc4.Latitude)));
var north = Math.Max(loc1.Latitude, Math.Max(loc2.Latitude, Math.Max(loc3.Latitude, loc4.Latitude)));
var p1 = ParentMap.MapTransform.Transform(new Location(south, west));
var p2 = ParentMap.MapTransform.Transform(new Location(north, east));
width = Math.Round((p2.X - p1.X) * ParentMap.ViewportScale);
height = Math.Round((p2.Y - p1.Y) * ParentMap.ViewportScale);
var image = GetBitmap(west, east, south, north, (int)width, (int)height);
UpdateImage(west, east, south, north, image);
}
UpdateImage(west, east, south, north, (BitmapSource)null);
}
}
private void UpdateImage(double west, double east, double south, double north, BitmapSource image)
protected virtual void UpdateImage(double west, double east, double south, double north, Uri uri)
{
UpdateImage(west, east, south, north, new BitmapImage(uri));
}
protected void UpdateImage(double west, double east, double south, double north, BitmapSource bitmap)
{
currentImageIndex = (currentImageIndex + 1) % 2;
var mapImage = (MapImage)Children[currentImageIndex];
mapImage.Source = null;
mapImage.North = double.NaN; // avoid frequent MapRectangle.UpdateData() calls
mapImage.West = west;
mapImage.East = east;
mapImage.South = south;
mapImage.North = north;
mapImage.Source = bitmap;
if (image != null)
{
mapImage.Source = image;
AddDownloadEventHandlers(image);
}
else
{
BlendImages();
}
ImageUpdated(bitmap);
}
private void BlendImages()
{
#if WINDOWS_RUNTIME
var duration = TimeSpan.Zero; // animation not working in Windows Runtime (?)
#else
var duration = Tile.AnimationDuration;
#endif
var mapImage = (MapImage)Children[currentImageIndex];
var fadeOut = new DoubleAnimation { To = 0d, Duration = duration };
var topImage = (MapImage)Children[currentImageIndex];
var bottomImage = (MapImage)Children[(currentImageIndex + 1) % 2];
if (mapImage.Source != null)
if (topImage.Source != null)
{
mapImage.BeginAnimation(UIElement.OpacityProperty,
new DoubleAnimation { To = 1d, Duration = duration });
fadeOut.BeginTime = duration;
topImage.BeginAnimation(UIElement.OpacityProperty,
new DoubleAnimation { To = 1d, Duration = Settings.TileAnimationDuration });
}
mapImage = (MapImage)Children[(currentImageIndex + 1) % 2];
mapImage.BeginAnimation(UIElement.OpacityProperty, fadeOut);
if (bottomImage.Source != null)
{
var fadeOutAnimation = new DoubleAnimation { To = 0d, Duration = Settings.TileAnimationDuration };
if (topImage.Source != null)
{
fadeOutAnimation.BeginTime = Settings.TileAnimationDuration;
}
bottomImage.BeginAnimation(UIElement.OpacityProperty, fadeOutAnimation);
}
updateInProgress = false;
}

View file

@ -72,7 +72,7 @@ namespace MapControl
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement element in InternalChildren)
foreach (UIElement element in Children)
{
var location = GetLocation(element);
@ -92,7 +92,7 @@ namespace MapControl
protected virtual void OnViewportChanged()
{
foreach (UIElement element in InternalChildren)
foreach (UIElement element in Children)
{
var location = GetLocation(element);

View file

@ -0,0 +1,24 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
#if WINDOWS_RUNTIME
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Media;
#endif
namespace MapControl
{
public partial class MapRectangle
{
private void SetRect(Rect rect)
{
((RectangleGeometry)Data).Rect = rect;
RenderTransform = ParentMap.ViewportTransform;
}
}
}

View file

@ -0,0 +1,40 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Windows;
using System.Windows.Media;
namespace MapControl
{
public partial class MapRectangle
{
static MapRectangle()
{
FillTransform.Freeze();
}
private void SetRect(Rect rect)
{
// Apply scaling to the RectangleGeometry to compensate for inaccurate hit testing in WPF.
// See http://stackoverflow.com/a/19335624/1136211
var scale = 1e6 / Math.Min(rect.Width, rect.Height);
rect.X *= scale;
rect.Y *= scale;
rect.Width *= scale;
rect.Height *= scale;
var scaleTransform = new ScaleTransform(1d / scale, 1d / scale);
scaleTransform.Freeze();
var transform = new TransformGroup();
transform.Children.Add(scaleTransform); // revert scaling
transform.Children.Add(ParentMap.ViewportTransform);
((RectangleGeometry)Data).Rect = rect;
RenderTransform = transform;
}
}
}

View file

@ -7,6 +7,7 @@ using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
#else
using System;
using System.Windows;
using System.Windows.Media;
#endif
@ -16,15 +17,15 @@ namespace MapControl
/// <summary>
/// Fills a rectangular area defined by South, North, West and East with a Brush.
/// </summary>
public class MapRectangle : MapPath
public partial class MapRectangle : MapPath
{
public static readonly DependencyProperty SouthProperty = DependencyProperty.Register(
"South", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
public static readonly DependencyProperty NorthProperty = DependencyProperty.Register(
"North", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
/// <summary>
/// Used in derived classes like MapImage.
/// </summary>
protected static readonly MatrixTransform FillTransform = new MatrixTransform
{
Matrix = new Matrix(1d, 0d, 0d, -1d, 0d, 1d)
};
public static readonly DependencyProperty WestProperty = DependencyProperty.Register(
"West", typeof(double), typeof(MapRectangle),
@ -34,24 +35,20 @@ namespace MapControl
"East", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
public static readonly DependencyProperty SouthProperty = DependencyProperty.Register(
"South", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
public static readonly DependencyProperty NorthProperty = DependencyProperty.Register(
"North", typeof(double), typeof(MapRectangle),
new PropertyMetadata(double.NaN, (o, e) => ((MapRectangle)o).UpdateData()));
public MapRectangle()
{
Data = new RectangleGeometry();
StrokeThickness = 0d;
}
public double South
{
get { return (double)GetValue(SouthProperty); }
set { SetValue(SouthProperty, value); }
}
public double North
{
get { return (double)GetValue(NorthProperty); }
set { SetValue(NorthProperty, value); }
}
public double West
{
get { return (double)GetValue(WestProperty); }
@ -64,6 +61,18 @@ namespace MapControl
set { SetValue(EastProperty, value); }
}
public double South
{
get { return (double)GetValue(SouthProperty); }
set { SetValue(SouthProperty, value); }
}
public double North
{
get { return (double)GetValue(NorthProperty); }
set { SetValue(NorthProperty, value); }
}
protected override void UpdateData()
{
var geometry = (RectangleGeometry)Data;
@ -73,25 +82,10 @@ namespace MapControl
!double.IsNaN(West) && !double.IsNaN(East) &&
South < North && West < East)
{
// Create a scaled RectangleGeometry due to inaccurate hit testing in WPF.
// See http://stackoverflow.com/a/19335624/1136211
const double scale = 1e6;
var p1 = ParentMap.MapTransform.Transform(new Location(South, West));
var p2 = ParentMap.MapTransform.Transform(new Location(North, East));
geometry.Rect = new Rect(p1.X * scale, p1.Y * scale, (p2.X - p1.X) * scale, (p2.Y - p1.Y) * scale);
var scaleTransform = new ScaleTransform // revert scaling
{
ScaleX = 1d / scale,
ScaleY = 1d / scale
};
scaleTransform.Freeze();
var transform = new TransformGroup();
transform.Children.Add(scaleTransform);
transform.Children.Add(ParentMap.ViewportTransform);
RenderTransform = transform;
SetRect(new Rect(p1.X, p1.Y, p2.X - p1.X, p2.Y - p1.Y));
}
else
{

View file

@ -19,17 +19,11 @@ namespace MapControl
/// </summary>
public class PanelBase : Panel
{
#if WINDOWS_RUNTIME || SILVERLIGHT
protected internal UIElementCollection InternalChildren
{
get { return Children; }
}
#endif
protected override Size MeasureOverride(Size availableSize)
{
availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
foreach (UIElement element in InternalChildren)
foreach (UIElement element in Children)
{
element.Measure(availableSize);
}
@ -39,7 +33,7 @@ namespace MapControl
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement child in InternalChildren)
foreach (UIElement child in Children)
{
child.Arrange(new Rect(new Point(), finalSize));
}

View file

@ -2,7 +2,10 @@
using System.Runtime.InteropServices;
using System.Windows;
#if SILVERLIGHT
#if WINDOWS_PHONE
[assembly: AssemblyTitle("XAML Map Control (Windows Phone Silverlight)")]
[assembly: AssemblyDescription("XAML Map Control Library for Windows Phone Silverlight")]
#elif SILVERLIGHT
[assembly: AssemblyTitle("XAML Map Control (Silverlight)")]
[assembly: AssemblyDescription("XAML Map Control Library for Silverlight")]
#else
@ -14,8 +17,8 @@ using System.Windows;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2014 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("2.2.0")]
[assembly: AssemblyFileVersion("2.2.0")]
[assembly: AssemblyVersion("2.3.0")]
[assembly: AssemblyFileVersion("2.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

32
MapControl/Settings.cs Normal file
View file

@ -0,0 +1,32 @@
// XAML Map Control - http://xamlmapcontrol.codeplex.com/
// Copyright © 2014 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
#if WINDOWS_RUNTIME
using Windows.UI.Xaml.Media.Animation;
#else
using System.Windows.Media.Animation;
#endif
namespace MapControl
{
/// <summary>
/// Stores global static properties that control the behaviour of the map control.
/// </summary>
public static class Settings
{
public static TimeSpan TileUpdateInterval { get; set; }
public static TimeSpan TileAnimationDuration { get; set; }
public static TimeSpan MapAnimationDuration { get; set; }
public static EasingFunctionBase MapAnimationEasingFunction { get; set; }
static Settings()
{
TileUpdateInterval = TimeSpan.FromSeconds(0.5);
TileAnimationDuration = TimeSpan.FromSeconds(0.3);
MapAnimationDuration = TimeSpan.FromSeconds(0.3);
MapAnimationEasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut };
}
}
}

View file

@ -40,6 +40,7 @@
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Template">
<Setter.Value>

View file

@ -35,7 +35,8 @@ namespace MapControl
}
else
{
Image.BeginAnimation(Image.OpacityProperty, new DoubleAnimation { To = 1d, Duration = AnimationDuration });
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation { To = 1d, Duration = Settings.TileAnimationDuration });
}
}
else
@ -55,7 +56,8 @@ namespace MapControl
bitmap.ImageOpened -= BitmapImageOpened;
bitmap.ImageFailed -= BitmapImageFailed;
Image.BeginAnimation(Image.OpacityProperty, new DoubleAnimation { To = 1d, Duration = AnimationDuration });
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation { To = 1d, Duration = Settings.TileAnimationDuration });
}
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)

View file

@ -27,7 +27,8 @@ namespace MapControl
}
else
{
Image.BeginAnimation(Image.OpacityProperty, new DoubleAnimation(1d, AnimationDuration));
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation(1d, Settings.TileAnimationDuration));
}
}
else
@ -47,7 +48,8 @@ namespace MapControl
bitmap.DownloadCompleted -= BitmapDownloadCompleted;
bitmap.DownloadFailed -= BitmapDownloadFailed;
Image.BeginAnimation(Image.OpacityProperty, new DoubleAnimation(1d, AnimationDuration));
Image.BeginAnimation(Image.OpacityProperty,
new DoubleAnimation(1d, Settings.TileAnimationDuration));
}
private void BitmapDownloadFailed(object sender, ExceptionEventArgs e)

View file

@ -13,8 +13,6 @@ namespace MapControl
{
public partial class Tile
{
public static TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.5);
public readonly int ZoomLevel;
public readonly int X;
public readonly int Y;

View file

@ -13,10 +13,8 @@ namespace MapControl
{
internal partial class TileContainer
{
private Matrix GetTileIndexMatrix(int numTiles)
private Matrix GetTileIndexMatrix(double scale)
{
var scale = (double)numTiles / 360d;
return ViewportTransform.Matrix
.Invert() // view to map coordinates
.Translate(180d, -180d)

View file

@ -9,9 +9,8 @@ namespace MapControl
{
internal partial class TileContainer
{
private Matrix GetTileIndexMatrix(int numTiles)
private Matrix GetTileIndexMatrix(double scale)
{
var scale = (double)numTiles / 360d;
var transform = ViewportTransform.Matrix;
transform.Invert(); // view to map coordinates
transform.Translate(180d, -180d);

View file

@ -19,11 +19,9 @@ namespace MapControl
{
internal partial class TileContainer : PanelBase
{
// relative scaled tile size ranges from 0.75 to 1.5 (192 to 384 pixels)
// relative size of scaled tile ranges from 0.75 to 1.5 (192 to 384 pixels)
private static double zoomLevelSwitchDelta = -Math.Log(0.75, 2d);
public static TimeSpan UpdateInterval = TimeSpan.FromSeconds(0.5);
private readonly DispatcherTimer updateTimer;
private Size viewportSize;
private Point viewportOrigin;
@ -38,26 +36,26 @@ namespace MapControl
public TileContainer()
{
RenderTransform = new MatrixTransform();
updateTimer = new DispatcherTimer { Interval = UpdateInterval };
updateTimer = new DispatcherTimer { Interval = Settings.TileUpdateInterval };
updateTimer.Tick += UpdateTiles;
}
public IEnumerable<TileLayer> TileLayers
{
get { return InternalChildren.Cast<TileLayer>(); }
get { return Children.Cast<TileLayer>(); }
}
public void AddTileLayers(int index, IEnumerable<TileLayer> tileLayers)
{
foreach (var tileLayer in tileLayers)
{
if (index < InternalChildren.Count)
if (index < Children.Count)
{
InternalChildren.Insert(index, tileLayer);
Children.Insert(index, tileLayer);
}
else
{
InternalChildren.Add(tileLayer);
Children.Add(tileLayer);
}
index++;
@ -69,19 +67,19 @@ namespace MapControl
{
while (count-- > 0)
{
((TileLayer)InternalChildren[index]).ClearTiles();
InternalChildren.RemoveAt(index);
((TileLayer)Children[index]).ClearTiles();
Children.RemoveAt(index);
}
}
public void ClearTileLayers()
{
foreach (TileLayer tileLayer in InternalChildren)
foreach (TileLayer tileLayer in Children)
{
tileLayer.ClearTiles();
}
InternalChildren.Clear();
Children.Clear();
}
public double SetViewportTransform(double mapZoomLevel, double mapRotation, Point mapOrigin, Point vpOrigin, Size vpSize)
@ -127,7 +125,8 @@ namespace MapControl
updateTimer.Stop();
var zoom = (int)Math.Floor(zoomLevel + zoomLevelSwitchDelta);
var transform = GetTileIndexMatrix(1 << zoom);
var scale = (double)(1 << zoom) / 360d;
var transform = GetTileIndexMatrix(scale);
// tile indices of visible rectangle
var p1 = transform.Transform(new Point(0d, 0d));
@ -149,7 +148,7 @@ namespace MapControl
UpdateRenderTransform();
foreach (TileLayer tileLayer in InternalChildren)
foreach (TileLayer tileLayer in Children)
{
tileLayer.UpdateTiles(tileZoomLevel, tileGrid);
}

View file

@ -13,9 +13,9 @@ namespace MapControl
/// <summary>
/// Loads map tile images.
/// </summary>
internal class TileImageLoader
internal class TileImageLoader : ITileImageLoader
{
internal void BeginGetTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
public void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
{
var imageTileSource = tileLayer.TileSource as ImageTileSource;
@ -48,7 +48,7 @@ namespace MapControl
}
}
internal void CancelGetTiles()
public void CancelLoadTiles(TileLayer tileLayer)
{
}
}

View file

@ -6,6 +6,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
@ -20,7 +21,7 @@ namespace MapControl
/// <summary>
/// Loads map tile images and optionally caches them in a System.Runtime.Caching.ObjectCache.
/// </summary>
public class TileImageLoader
public class TileImageLoader : ITileImageLoader
{
/// <summary>
/// Default Name of an ObjectCache instance that is assigned to the Cache property.
@ -33,39 +34,27 @@ namespace MapControl
public static readonly string DefaultCacheDirectory =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl");
/// <summary>
/// Default expiration time span for cached images. Used when no expiration date
/// was transmitted on download. The default value is seven days.
/// </summary>
public static TimeSpan DefaultCacheExpiration { get; set; }
/// <summary>
/// The ObjectCache used to cache tile images. The default is MemoryCache.Default.
/// </summary>
public static ObjectCache Cache { get; set; }
/// <summary>
/// The time interval after which cached images expire. The default value is seven days.
/// When an image is not retrieved from the cache during this interval it is considered as expired
/// and will be removed from the cache, provided that the cache implementation supports expiration.
/// If an image is retrieved from the cache and the CacheUpdateAge time interval has expired,
/// the image is downloaded again and rewritten to the cache with a new expiration time.
/// </summary>
public static TimeSpan CacheExpiration { get; set; }
/// <summary>
/// The time interval after which a cached image is updated and rewritten to the cache.
/// The default value is one day. This time interval should not be greater than the value
/// of the CacheExpiration property.
/// If CacheUpdateAge is less than or equal to TimeSpan.Zero, cached images are never updated.
/// </summary>
public static TimeSpan CacheUpdateAge { get; set; }
static TileImageLoader()
{
DefaultCacheExpiration = TimeSpan.FromDays(7);
Cache = MemoryCache.Default;
CacheExpiration = TimeSpan.FromDays(7);
CacheUpdateAge = TimeSpan.FromDays(1);
}
private readonly ConcurrentQueue<Tile> pendingTiles = new ConcurrentQueue<Tile>();
private int threadCount;
internal void BeginGetTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
public void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
{
if (tiles.Any())
{
@ -96,7 +85,7 @@ namespace MapControl
}
}
internal void CancelGetTiles()
public void CancelLoadTiles(TileLayer tileLayer)
{
Tile tile;
while (pendingTiles.TryDequeue(out tile)) ; // no Clear method
@ -119,7 +108,7 @@ namespace MapControl
{
pendingTiles.Enqueue(tile); // not yet cached
}
else if (CacheUpdateAge > TimeSpan.Zero && TileCache.CreationTime(buffer) + CacheUpdateAge < DateTime.UtcNow)
else if (TileCache.IsExpired(buffer))
{
dispatcher.Invoke(setImageAction, tile, image); // synchronously before enqueuing
outdatedTiles.Add(tile); // update outdated cache
@ -154,7 +143,6 @@ namespace MapControl
while (pendingTiles.TryDequeue(out tile))
{
byte[] buffer = null;
ImageSource image = null;
if (imageTileSource != null)
@ -167,14 +155,24 @@ namespace MapControl
if (uri != null)
{
if (uri.Scheme == "file") // create from FileStream because creating from URI leaves the file open
if (uri.Scheme == "file") // create from FileStream because creating from Uri leaves the file open
{
image = CreateImage(uri.LocalPath);
}
else
{
buffer = DownloadImage(uri);
DateTime expirationTime;
var buffer = DownloadImage(uri, out expirationTime);
image = CreateImage(buffer);
if (image != null &&
Cache != null &&
!string.IsNullOrWhiteSpace(sourceName) &&
expirationTime > DateTime.UtcNow)
{
Cache.Set(TileCache.Key(sourceName, tile), buffer, new CacheItemPolicy { AbsoluteExpiration = expirationTime });
}
}
}
}
@ -183,11 +181,6 @@ namespace MapControl
{
dispatcher.BeginInvoke(setImageAction, tile, image);
}
if (image != null && buffer != null && Cache != null && !string.IsNullOrWhiteSpace(sourceName))
{
Cache.Set(TileCache.Key(sourceName, tile), buffer, new CacheItemPolicy { SlidingExpiration = CacheExpiration });
}
}
Interlocked.Decrement(ref threadCount);
@ -253,20 +246,33 @@ namespace MapControl
return image;
}
private static byte[] DownloadImage(Uri uri)
private static byte[] DownloadImage(Uri uri, out DateTime expirationTime)
{
expirationTime = DateTime.UtcNow + DefaultCacheExpiration;
byte[] buffer = null;
try
{
var request = (HttpWebRequest)WebRequest.Create(uri);
request.UserAgent = "XAML Map Control";
var request = HttpWebRequest.CreateHttp(uri);
using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = response.GetResponseStream())
{
buffer = TileCache.CreateBuffer(responseStream, (int)response.ContentLength);
var expiresHeader = response.Headers["Expires"];
DateTime expires;
if (expiresHeader != null &&
DateTime.TryParse(expiresHeader, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out expires) &&
expirationTime > expires)
{
expirationTime = expires;
}
buffer = TileCache.CreateBuffer(responseStream, (int)response.ContentLength, expirationTime);
}
//Trace.TraceInformation("Downloaded {0}, expires {1}", uri, expirationTime);
}
catch (WebException ex)
{
@ -305,18 +311,16 @@ namespace MapControl
return new MemoryStream(cacheBuffer, imageBufferOffset, cacheBuffer.Length - imageBufferOffset, false);
}
public static DateTime CreationTime(byte[] cacheBuffer)
public static bool IsExpired(byte[] cacheBuffer)
{
return DateTime.FromBinary(BitConverter.ToInt64(cacheBuffer, 0));
return DateTime.FromBinary(BitConverter.ToInt64(cacheBuffer, 0)) < DateTime.UtcNow;
}
public static byte[] CreateBuffer(Stream imageStream, int length)
public static byte[] CreateBuffer(Stream imageStream, int length, DateTime expirationTime)
{
var creationTime = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());
using (var memoryStream = length > 0 ? new MemoryStream(length + imageBufferOffset) : new MemoryStream())
{
memoryStream.Write(creationTime, 0, imageBufferOffset);
memoryStream.Write(BitConverter.GetBytes(expirationTime.ToBinary()), 0, imageBufferOffset);
imageStream.CopyTo(memoryStream);
return length > 0 ? memoryStream.GetBuffer() : memoryStream.ToArray();

View file

@ -20,13 +20,13 @@ namespace MapControl
/// <summary>
/// Loads map tile images.
/// </summary>
public class TileImageLoader
public class TileImageLoader : ITileImageLoader
{
public static IObjectCache Cache { get; set; }
private HttpClient httpClient;
internal void BeginGetTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
public void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles)
{
var imageTileSource = tileLayer.TileSource as ImageTileSource;
@ -69,7 +69,7 @@ namespace MapControl
}
}
internal void CancelGetTiles()
public void CancelLoadTiles(TileLayer tileLayer)
{
}

View file

@ -7,16 +7,24 @@ using System.Collections.Generic;
using System.Linq;
#if WINDOWS_RUNTIME
using Windows.Foundation;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
#else
using System.Windows;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
#endif
namespace MapControl
{
public interface ITileImageLoader
{
void BeginLoadTiles(TileLayer tileLayer, IEnumerable<Tile> tiles);
void CancelLoadTiles(TileLayer tileLayer);
}
/// <summary>
/// Fills a rectangular area with map tiles from a TileSource.
/// </summary>
@ -34,29 +42,35 @@ namespace MapControl
return new TileLayer
{
SourceName = "OpenStreetMap",
Description = "© {y} OpenStreetMap Contributors, CC-BY-SA",
TileSource = new TileSource("http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png")
Description="© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)",
TileSource = new TileSource { UriFormat = "http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png" }
};
}
}
private readonly TileImageLoader tileImageLoader = new TileImageLoader();
private string description = string.Empty;
private readonly ITileImageLoader tileImageLoader;
private TileSource tileSource;
private List<Tile> tiles = new List<Tile>();
private Int32Rect grid;
private int zoomLevel;
private Int32Rect grid;
public TileLayer()
: this(new TileImageLoader())
{
}
public TileLayer(ITileImageLoader tileImageLoader)
{
this.tileImageLoader = tileImageLoader;
MinZoomLevel = 0;
MaxZoomLevel = 18;
MaxParallelDownloads = 8;
MaxParallelDownloads = 4;
LoadLowerZoomLevels = true;
AnimateTileOpacity = true;
}
public string SourceName { get; set; }
public string Description { get; set; }
public int MinZoomLevel { get; set; }
public int MaxZoomLevel { get; set; }
public int MaxParallelDownloads { get; set; }
@ -64,10 +78,14 @@ namespace MapControl
public bool AnimateTileOpacity { get; set; }
public Brush Foreground { get; set; }
public string Description
/// <summary>
/// In case the Description text contains copyright links in markdown syntax [text](url),
/// the DescriptionInlines property may be used to create a collection of Run and Hyperlink
/// inlines to be displayed in e.g. a TextBlock or a Silverlight RichTextBlock.
/// </summary>
public ICollection<Inline> DescriptionInlines
{
get { return description; }
set { description = value.Replace("{y}", DateTime.Now.Year.ToString()); }
get { return Description.ToInlines(); }
}
public TileSource TileSource
@ -79,42 +97,43 @@ namespace MapControl
if (grid.Width > 0 && grid.Height > 0)
{
tileImageLoader.CancelGetTiles();
tiles.Clear();
if (tileSource != null)
{
SelectTiles();
RenderTiles();
tileImageLoader.BeginGetTiles(this, tiles.Where(t => !t.HasImageSource));
}
else
{
RenderTiles();
}
ClearTiles();
UpdateTiles();
}
}
}
internal void UpdateTiles(int zoomLevel, Int32Rect grid)
{
this.grid = grid;
this.zoomLevel = zoomLevel;
if (tileSource != null)
{
tileImageLoader.CancelGetTiles();
SelectTiles();
RenderTiles();
tileImageLoader.BeginGetTiles(this, tiles.Where(t => !t.HasImageSource));
}
}
internal void ClearTiles()
{
tileImageLoader.CancelGetTiles();
tileImageLoader.CancelLoadTiles(this);
tiles.Clear();
RenderTiles();
Children.Clear();
}
internal void UpdateTiles(int zoomLevel, Int32Rect grid)
{
this.zoomLevel = zoomLevel;
this.grid = grid;
UpdateTiles();
}
private void UpdateTiles()
{
if (tileSource != null)
{
tileImageLoader.CancelLoadTiles(this);
SelectTiles();
Children.Clear();
foreach (var tile in tiles)
{
Children.Add(tile.Image);
}
tileImageLoader.BeginLoadTiles(this, tiles.Where(t => !t.HasImageSource));
}
}
private void SelectTiles()
@ -122,7 +141,9 @@ namespace MapControl
var maxZoomLevel = Math.Min(zoomLevel, MaxZoomLevel);
var minZoomLevel = maxZoomLevel;
if (LoadLowerZoomLevels && Parent is TileContainer && ((TileContainer)Parent).TileLayers.FirstOrDefault() == this)
if (LoadLowerZoomLevels &&
Parent is TileContainer &&
((TileContainer)Parent).TileLayers.FirstOrDefault() == this)
{
minZoomLevel = MinZoomLevel;
}
@ -165,16 +186,6 @@ namespace MapControl
tiles = newTiles;
}
private void RenderTiles()
{
InternalChildren.Clear();
foreach (var tile in tiles)
{
InternalChildren.Add(tile.Image);
}
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (var tile in tiles)

View file

@ -4,7 +4,6 @@
using System;
using System.Globalization;
using System.Text;
#if WINDOWS_RUNTIME
using Windows.Foundation;
#else
@ -28,10 +27,9 @@ namespace MapControl
{
}
public TileSource(string uriFormat)
: this()
protected TileSource(string uriFormat)
{
UriFormat = uriFormat;
this.uriFormat = uriFormat;
}
public string UriFormat
@ -147,16 +145,16 @@ namespace MapControl
return null;
}
var key = new StringBuilder { Length = zoomLevel };
var quadkey = new char[zoomLevel];
for (var z = zoomLevel - 1; z >= 0; z--, x /= 2, y /= 2)
{
key[z] = (char)('0' + 2 * (y % 2) + (x % 2));
quadkey[z] = (char)('0' + 2 * (y % 2) + (x % 2));
}
return new Uri(uriFormat.
Replace("{i}", key.ToString(key.Length - 1, 1)).
Replace("{q}", key.ToString()));
Replace("{i}", new string(quadkey[zoomLevel - 1], 1)).
Replace("{q}", new string(quadkey)));
}
private Uri GetBoundingBoxUri(int x, int y, int zoomLevel)

View file

@ -17,7 +17,7 @@ namespace MapControl
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return new TileSource(value as string);
return new TileSource { UriFormat = value as string };
}
}

View file

@ -36,12 +36,21 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\BingMapsTileLayer.cs">
<Link>BingMapsTileLayer.cs</Link>
</Compile>
<Compile Include="..\BingMapsTileSource.cs">
<Link>BingMapsTileSource.cs</Link>
</Compile>
<Compile Include="..\Extensions.Silverlight.WinRT.cs">
<Link>Extensions.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\Extensions.WinRT.cs">
<Link>Extensions.WinRT.cs</Link>
</Compile>
<Compile Include="..\HyperlinkText.cs">
<Link>HyperlinkText.cs</Link>
</Compile>
<Compile Include="..\ImageFileCache.WinRT.cs">
<Link>ImageFileCache.WinRT.cs</Link>
</Compile>
@ -120,6 +129,9 @@
<Compile Include="..\MapRectangle.cs">
<Link>MapRectangle.cs</Link>
</Compile>
<Compile Include="..\MapRectangle.Silverlight.WinRT.cs">
<Link>MapRectangle.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\MapTransform.cs">
<Link>MapTransform.cs</Link>
</Compile>
@ -132,6 +144,9 @@
<Compile Include="..\Pushpin.Silverlight.WinRT.cs">
<Link>Pushpin.Silverlight.WinRT.cs</Link>
</Compile>
<Compile Include="..\Settings.cs">
<Link>Settings.cs</Link>
</Compile>
<Compile Include="..\Tile.cs">
<Link>Tile.cs</Link>
</Compile>
@ -163,16 +178,17 @@
<Link>MapControl.snk</Link>
</None>
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<TargetPlatform Include="Windows, Version=8.1" />
<TargetPlatform Include="WindowsPhoneApp, Version=8.1" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Page Include="Themes\Generic.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '12.0' ">
<VisualStudioVersion>12.0</VisualStudioVersion>
</PropertyGroup>

View file

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

View file

@ -40,6 +40,7 @@
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Template">
<Setter.Value>

View file

@ -1,18 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

View file

@ -7,30 +7,58 @@
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<map:TileLayerCollection x:Key="TileLayers">
<map:TileLayer SourceName="OpenStreetMap" Description="© {y} OpenStreetMap Contributors, CC-BY-SA">
<!--
TileLayers with OpenStreetMap data.
-->
<map:TileLayer SourceName="OpenStreetMap"
Description="Maps © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
MaxZoomLevel="19">
<map:TileSource UriFormat="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="OpenCycleMap" Description="OpenCycleMap - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA">
<map:TileSource UriFormat="http://{c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest OpenCycleMap"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="OCM Transport" Description="OpenCycleMap Transport - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA">
<map:TileSource UriFormat="http://{c}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Landscape"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="OCM Landscape" Description="OpenCycleMap Landscape - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA">
<map:TileSource UriFormat="http://{c}.tile3.opencyclemap.org/landscape/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Outdoors"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="MapQuest OSM" Description="MapQuest OSM - © {y} MapQuest &amp; OpenStreetMap Contributors">
<map:TileLayer SourceName="Thunderforest Transport"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/transport/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="Thunderforest Transport Dark"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="Google Maps" Description="Google Maps - © {y} Google" MaxZoomLevel="20">
<map:TileSource UriFormat="http://mt{i}.google.com/vt/x={x}&amp;y={y}&amp;z={z}"/>
</map:TileLayer>
<map:TileLayer SourceName="Bing Maps" Description="Bing Maps - © {y} Microsoft Corporation" MinZoomLevel="1" MaxZoomLevel="19">
<map:TileSource UriFormat="http://ecn.t{i}.tiles.virtualearth.net/tiles/r{q}.png?g=0&amp;stl=h"/>
</map:TileLayer>
<map:TileLayer SourceName="Seamarks" Description="© {y} OpenSeaMap Contributors, CC-BY-SA" MinZoomLevel="10" MaxZoomLevel="18">
<map:TileLayer SourceName="Seamarks" Description="© OpenSeaMap Contributors"
MinZoomLevel="10" MaxZoomLevel="18">
<map:TileSource UriFormat="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"/>
</map:TileLayer>
<!--
Bing Maps TileLayers with tile URLs retrieved from the Imagery Metadata Service
(see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
A Bing Maps API Key (see http://msdn.microsoft.com/en-us/library/ff428642.aspx) is required
for using these layers and must be assigned to the static BingMapsTileLayer.ApiKey property.
-->
<map:BingMapsTileLayer SourceName="Bing Maps Road"
Description="Bing Maps - © Microsoft Corporation"
Mode="Road" MaxZoomLevel="19"/>
<map:BingMapsTileLayer SourceName="Bing Maps Aerial"
Description="Bing Maps - © Microsoft Corporation"
Mode="Aerial" MaxZoomLevel="19" Foreground="White" Background="Black"/>
<map:BingMapsTileLayer SourceName="Bing Maps Hybrid"
Description="Bing Maps - © Microsoft Corporation"
Mode="AerialWithLabels" MaxZoomLevel="19" Foreground="White" Background="Black"/>
</map:TileLayerCollection>
<local:ObjectReferenceConverter x:Key="ObjectReferenceConverter"/>
</Page.Resources>
@ -43,6 +71,7 @@
<map:MapBase.Center>
<map:Location Latitude="53.5" Longitude="8.2"/>
</map:MapBase.Center>
<map:MapGraticule Opacity="0.6"/>
<Canvas map:MapPanel.Location="{Binding Location}"
@ -65,7 +94,12 @@
</Path>
</Canvas>
</map:MapBase>
<Border HorizontalAlignment="Stretch" VerticalAlignment="Top" Background="#7F000000">
<TextBlock x:Name="mapLegend" Margin="2" FontSize="12"/>
</Border>
</Grid>
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Label="Map">
@ -83,13 +117,16 @@
</AppBarButton.Icon>
<AppBarButton.Flyout>
<MenuFlyout>
<MenuFlyoutItem Text="OpenStreetMap" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="OpenCycleMap" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="OCM Transport" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="OCM Landscape" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="MapQuest OSM" Click="MapMenuItemClick"/>
<!--<MenuFlyoutItem Text="Google Maps" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Bing Maps" Click="MapMenuItemClick"/>-->
<MenuFlyoutItem Text="OpenStreetMap" Tag="OpenStreetMap" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="OpenCycleMap" Tag="Thunderforest OpenCycleMap" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Landscape" Tag="Thunderforest Landscape" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Outdoors" Tag="Thunderforest Outdoors" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Transport" Tag="Thunderforest Transport" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Transport Dark" Tag="Thunderforest Transport Dark" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="MapQuest Open" Tag="MapQuest OpenStreetMap" Click="MapMenuItemClick"/>
<!--<MenuFlyoutItem Text="Bing Maps Road" Tag="Bing Maps Road" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Bing Maps Aerial" Tag="Bing Maps Aerial" Click="MapMenuItemClick"/>
<MenuFlyoutItem Text="Bing Maps Hybrid" Tag="Bing Maps Hybrid" Click="MapMenuItemClick"/>-->
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>

View file

@ -10,38 +10,49 @@ namespace PhoneApplication
{
public sealed partial class MainPage : Page
{
private TileLayerCollection tileLayers;
private bool manipulationActive;
public MainPage()
{
TileImageLoader.Cache = new ImageFileCache();
//BingMapsTileLayer.ApiKey = ...
InitializeComponent();
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[0];
tileLayers = (TileLayerCollection)Resources["TileLayers"];
SetTileLayer(tileLayers[0].SourceName);
DataContext = new ViewModel(Dispatcher);
NavigationCacheMode = NavigationCacheMode.Required;
}
private void SetTileLayer(string tileLayer)
{
map.TileLayer = tileLayers[tileLayer];
mapLegend.Inlines.Clear();
foreach (var inline in map.TileLayer.DescriptionInlines)
{
mapLegend.Inlines.Add(inline);
}
}
private void SeamarksChecked(object sender, RoutedEventArgs e)
{
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayers.Add((TileLayer)tileLayers["Seamarks"]);
}
private void SeamarksUnchecked(object sender, RoutedEventArgs e)
{
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayers.Remove((TileLayer)tileLayers["Seamarks"]);
}
private void MapMenuItemClick(object sender, RoutedEventArgs e)
{
var selectedValue = ((MenuFlyoutItem)sender).Text;
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[selectedValue];
var selectedItem = (MenuFlyoutItem)sender;
SetTileLayer((string)selectedItem.Tag);
}
private void CenterButtonClick(object sender, RoutedEventArgs e)

View file

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

View file

@ -63,10 +63,7 @@ namespace PhoneApplication
if (args.Status != PositionStatus.Initializing &&
args.Status != PositionStatus.Ready)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
Location = null;
});
await dispatcher.RunAsync(CoreDispatcherPriority.Low, () => Location = null);
}
}

View file

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

View file

@ -4,25 +4,58 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:map="clr-namespace:MapControl;assembly=MapControl.Silverlight"
xmlns:vm="clr-namespace:ViewModel"
xmlns:local="clr-namespace:SilverlightApplication"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<map:TileLayerCollection x:Key="TileLayers">
<map:TileLayer SourceName="OpenStreetMap" Description="© {y} OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="OpenCycleMap" Description="OpenCycleMap - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="OCM Transport" Description="OpenCycleMap Transport - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="OCM Landscape" Description="OpenCycleMap Landscape - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile3.opencyclemap.org/landscape/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="MapQuest OSM" Description="MapQuest OSM - © {y} MapQuest &amp; OpenStreetMap Contributors"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Seamarks" Description="© {y} OpenSeaMap Contributors, CC-BY-SA"
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" MinZoomLevel="10" MaxZoomLevel="18"/>
<!--
TileLayers with OpenStreetMap data.
-->
<map:TileLayer SourceName="OpenStreetMap"
Description="Maps © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"
MaxZoomLevel="19"/>
<map:TileLayer SourceName="Thunderforest OpenCycleMap"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Landscape"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Outdoors"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Transport"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/transport/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Transport Dark"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png"
Background="Black" Foreground="White"/>
<map:TileLayer SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"
MaxZoomLevel="19"/>
<map:TileLayer SourceName="Seamarks"
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"
MinZoomLevel="10" MaxZoomLevel="18"/>
<!--
Bing Maps TileLayers with tile URLs retrieved from the Imagery Metadata Service
(see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
A Bing Maps API Key (see http://msdn.microsoft.com/en-us/library/ff428642.aspx) is required
for using these layers and must be assigned to the static BingMapsTileLayer.ApiKey property.
-->
<map:BingMapsTileLayer SourceName="Bing Maps Road"
Description="© [Microsoft Corporation](http://www.bing.com/maps/)"
Mode="Road" MaxZoomLevel="19"/>
<map:BingMapsTileLayer SourceName="Bing Maps Aerial"
Description="© [Microsoft Corporation](http://www.bing.com/maps/)"
Mode="Aerial" MaxZoomLevel="19" Foreground="White" Background="Black"/>
<map:BingMapsTileLayer SourceName="Bing Maps Hybrid"
Description="© [Microsoft Corporation](http://www.bing.com/maps/)"
Mode="AerialWithLabels" MaxZoomLevel="19" Foreground="White" Background="Black"/>
</map:TileLayerCollection>
<DataTemplate x:Key="PolylineItemTemplate">
<map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/>
@ -127,9 +160,10 @@
<map:Pushpin map:MapPanel.Location="53.5,8.2" Background="Yellow" Foreground="Blue" Content="N 53° 30' E 8° 12'"/>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="4" FontSize="10"
Text="{Binding TileLayer.Description, ElementName=map}"/>
</map:Map>
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#7FFFFFFF">
<RichTextBlock x:Name="mapLegend" Margin="4,2" FontSize="10"/>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
@ -154,13 +188,20 @@
<Slider Width="100" Minimum="0" Maximum="1"
Value="{Binding Opacity, ElementName=mapImage, Mode=TwoWay}"/>
</StackPanel>
<CheckBox Margin="5" VerticalAlignment="Bottom" Content="Seamarks" Checked="SeamarksChecked" Unchecked="SeamarksUnchecked"/>
<ComboBox x:Name="tileLayerComboBox" Margin="5" VerticalAlignment="Bottom" Width="120" SelectionChanged="TileLayerSelectionChanged">
<sys:String>OpenStreetMap</sys:String>
<sys:String>OpenCycleMap</sys:String>
<sys:String>OCM Transport</sys:String>
<sys:String>OCM Landscape</sys:String>
<sys:String>MapQuest OSM</sys:String>
<CheckBox Margin="5" VerticalAlignment="Bottom" Content="Seamarks"
Checked="SeamarksChecked" Unchecked="SeamarksUnchecked"/>
<ComboBox x:Name="tileLayerComboBox" Width="130" Margin="5" VerticalAlignment="Bottom"
SelectionChanged="TileLayerSelectionChanged">
<ComboBoxItem Tag="OpenStreetMap">OpenStreetMap</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest OpenCycleMap">OpenCycleMap</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Landscape">Landscape</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Outdoors">Outdoors</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Transport">Transport</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Transport Dark">Transport Dark</ComboBoxItem>
<ComboBoxItem Tag="MapQuest OpenStreetMap">MapQuest Open</ComboBoxItem>
<!--<ComboBoxItem Tag="Bing Maps Road">Bing Maps Road</ComboBoxItem>
<ComboBoxItem Tag="Bing Maps Aerial">Bing Maps Aerial</ComboBoxItem>
<ComboBoxItem Tag="Bing Maps Hybrid">Bing Maps Hybrid</ComboBoxItem>-->
</ComboBox>
</StackPanel>
</Grid>

View file

@ -2,6 +2,7 @@
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using MapControl;
@ -9,9 +10,15 @@ namespace SilverlightApplication
{
public partial class MainPage : UserControl
{
private TileLayerCollection tileLayers;
public MainPage()
{
//BingMapsTileLayer.ApiKey = ...
InitializeComponent();
tileLayers = (TileLayerCollection)Resources["TileLayers"];
tileLayerComboBox.SelectedIndex = 0;
}
@ -48,19 +55,29 @@ namespace SilverlightApplication
private void TileLayerSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var comboBox = (ComboBox)sender;
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[(string)comboBox.SelectedItem];
var selectedItem = (ComboBoxItem)tileLayerComboBox.SelectedItem;
map.TileLayer = tileLayers[(string)selectedItem.Tag];
var paragraph = new Paragraph();
foreach (var inline in map.TileLayer.DescriptionInlines)
{
paragraph.Inlines.Add(inline);
}
mapLegend.Blocks.Clear();
mapLegend.Blocks.Add(paragraph);
}
private void SeamarksChecked(object sender, RoutedEventArgs e)
{
map.TileLayers.Add((TileLayer)((TileLayerCollection)Resources["TileLayers"])["Seamarks"]);
map.TileLayers.Add(tileLayers["Seamarks"]);
}
private void SeamarksUnchecked(object sender, RoutedEventArgs e)
{
map.TileLayers.Remove((TileLayer)((TileLayerCollection)Resources["TileLayers"])["Seamarks"]);
map.TileLayers.Remove(tileLayers["Seamarks"]);
}
}
}

View file

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

View file

@ -7,30 +7,58 @@
xmlns:local="using:StoreApplication">
<Page.Resources>
<map:TileLayerCollection x:Key="TileLayers">
<map:TileLayer SourceName="OpenStreetMap" Description="© {y} OpenStreetMap Contributors, CC-BY-SA">
<!--
TileLayers with OpenStreetMap data.
-->
<map:TileLayer SourceName="OpenStreetMap"
Description="Maps © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
MaxZoomLevel="19">
<map:TileSource UriFormat="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="OpenCycleMap" Description="OpenCycleMap - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA">
<map:TileSource UriFormat="http://{c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest OpenCycleMap"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="OCM Transport" Description="OpenCycleMap Transport - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA">
<map:TileSource UriFormat="http://{c}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Landscape"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="OCM Landscape" Description="OpenCycleMap Landscape - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA">
<map:TileSource UriFormat="http://{c}.tile3.opencyclemap.org/landscape/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Outdoors"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="MapQuest OSM" Description="MapQuest OSM - © {y} MapQuest &amp; OpenStreetMap Contributors">
<map:TileLayer SourceName="Thunderforest Transport"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/transport/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="Thunderforest Transport Dark"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://{c}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png"/>
</map:TileLayer>
<map:TileLayer SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:TileSource UriFormat="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"/>
</map:TileLayer>
<!--<map:TileLayer SourceName="Bing Maps" Description="Bing Maps - © {y} Microsoft Corporation" MinZoomLevel="1" MaxZoomLevel="19">
<map:TileSource UriFormat="http://ecn.t{i}.tiles.virtualearth.net/tiles/r{q}.png?g=0&amp;stl=h"/>
</map:TileLayer>
<map:TileLayer SourceName="Bing Images" Description="Bing Maps - © {y} Microsoft Corporation" MinZoomLevel="1" MaxZoomLevel="19" Background="#FF3F3F3F" Foreground="White">
<map:TileSource UriFormat="http://ecn.t{i}.tiles.virtualearth.net/tiles/a{q}.jpeg?g=0"/>
</map:TileLayer>-->
<map:TileLayer SourceName="Seamarks" Description="© {y} OpenSeaMap Contributors, CC-BY-SA" MinZoomLevel="10" MaxZoomLevel="18">
<map:TileLayer SourceName="Seamarks" Description="© OpenSeaMap Contributors"
MinZoomLevel="10" MaxZoomLevel="18">
<map:TileSource UriFormat="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"/>
</map:TileLayer>
<!--
Bing Maps TileLayers with tile URLs retrieved from the Imagery Metadata Service
(see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
A Bing Maps API Key (see http://msdn.microsoft.com/en-us/library/ff428642.aspx) is required
for using these layers and must be assigned to the static BingMapsTileLayer.ApiKey property.
-->
<map:BingMapsTileLayer SourceName="Bing Maps Road"
Description="Bing Maps - © Microsoft Corporation"
Mode="Road" MaxZoomLevel="19"/>
<map:BingMapsTileLayer SourceName="Bing Maps Aerial"
Description="Bing Maps - © Microsoft Corporation"
Mode="Aerial" MaxZoomLevel="19" Foreground="White" Background="Black"/>
<map:BingMapsTileLayer SourceName="Bing Maps Hybrid"
Description="Bing Maps - © Microsoft Corporation"
Mode="AerialWithLabels" MaxZoomLevel="19" Foreground="White" Background="Black"/>
</map:TileLayerCollection>
<DataTemplate x:Key="PolylineItemTemplate">
<map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/>
@ -162,10 +190,10 @@
<map:Location Latitude="53.5" Longitude="8.2"/>
</map:MapPanel.Location>
</map:Pushpin>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="4" FontSize="10"
Text="{Binding TileLayer.Description, ElementName=map}"/>
</map:Map>
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#BFFFFFFF">
<TextBlock x:Name="mapLegend" Margin="2" FontSize="10" Foreground="Black"/>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
@ -188,16 +216,20 @@
<TextBlock Text="Image Opacity" HorizontalAlignment="Center" Foreground="Gray" FontSize="14"/>
<Slider Margin="10,-10,10,-10" Width="200" Value="50" ValueChanged="ImageOpacitySliderValueChanged"/>
</StackPanel>
<CheckBox Margin="10" VerticalAlignment="Center" Content="Seamarks" Checked="SeamarksChecked" Unchecked="SeamarksUnchecked"/>
<ComboBox Margin="10" Width="200" VerticalAlignment="Center" SelectedValuePath="Content"
Loaded="TileLayerComboBoxLoaded" SelectionChanged="TileLayerSelectionChanged">
<ComboBoxItem>OpenStreetMap</ComboBoxItem>
<ComboBoxItem>OpenCycleMap</ComboBoxItem>
<ComboBoxItem>OCM Transport</ComboBoxItem>
<ComboBoxItem>OCM Landscape</ComboBoxItem>
<ComboBoxItem>MapQuest OSM</ComboBoxItem>
<!--<ComboBoxItem>Bing Maps</ComboBoxItem>
<ComboBoxItem>Bing Images</ComboBoxItem>-->
<CheckBox Margin="10" VerticalAlignment="Center" Content="Seamarks"
Checked="SeamarksChecked" Unchecked="SeamarksUnchecked"/>
<ComboBox x:Name="tileLayerComboBox" Width="200" Margin="10" VerticalAlignment="Center"
SelectionChanged="TileLayerSelectionChanged">
<ComboBoxItem Tag="OpenStreetMap">OpenStreetMap</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest OpenCycleMap">OpenCycleMap</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Landscape">Landscape</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Outdoors">Outdoors</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Transport">Transport</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Transport Dark">Transport Dark</ComboBoxItem>
<ComboBoxItem Tag="MapQuest OpenStreetMap">MapQuest Open</ComboBoxItem>
<!--<ComboBoxItem Tag="Bing Maps Road">Bing Maps Road</ComboBoxItem>
<ComboBoxItem Tag="Bing Maps Aerial">Bing Maps Aerial</ComboBoxItem>
<ComboBoxItem Tag="Bing Maps Hybrid">Bing Maps Hybrid</ComboBoxItem>-->
</ComboBox>
</StackPanel>
</Grid>

View file

@ -1,5 +1,4 @@
using MapControl;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
@ -8,14 +7,17 @@ namespace StoreApplication
{
public sealed partial class MainPage : Page
{
private TileLayerCollection tileLayers;
public MainPage()
{
TileImageLoader.Cache = new ImageFileCache();
//BingMapsTileLayer.ApiKey = ...
this.InitializeComponent();
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[0];
tileLayers = (TileLayerCollection)Resources["TileLayers"];
tileLayerComboBox.SelectedIndex = 0;
}
private void ImageOpacitySliderValueChanged(object sender, RangeBaseValueChangedEventArgs e)
@ -26,28 +28,28 @@ namespace StoreApplication
}
}
private void TileLayerComboBoxLoaded(object sender, RoutedEventArgs e)
{
((ComboBox)sender).SelectedIndex = 0;
}
private void TileLayerSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedValue = (string)((ComboBox)sender).SelectedValue;
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayer = tileLayers[selectedValue];
var selectedItem = (ComboBoxItem)tileLayerComboBox.SelectedItem;
map.TileLayer = tileLayers[(string)selectedItem.Tag];
mapLegend.Inlines.Clear();
foreach (var inline in map.TileLayer.DescriptionInlines)
{
mapLegend.Inlines.Add(inline);
}
}
private void SeamarksChecked(object sender, RoutedEventArgs e)
{
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayers.Add((TileLayer)tileLayers["Seamarks"]);
map.TileLayers.Add(tileLayers["Seamarks"]);
}
private void SeamarksUnchecked(object sender, RoutedEventArgs e)
{
var tileLayers = (TileLayerCollection)Resources["TileLayers"];
map.TileLayers.Remove((TileLayer)tileLayers["Seamarks"]);
map.TileLayers.Remove(tileLayers["Seamarks"]);
}
}
}

View file

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

View file

@ -9,48 +9,75 @@
Stylus.IsPressAndHoldEnabled="False">
<Window.Resources>
<map:TileLayerCollection x:Key="TileLayers">
<map:TileLayer SourceName="OpenStreetMap" Description="© {y} OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="OpenCycleMap" Description="OpenCycleMap - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="OCM Transport" Description="OpenCycleMap Transport - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile2.opencyclemap.org/transport/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="OCM Landscape" Description="OpenCycleMap Landscape - © {y} Andy Allen &amp; OpenStreetMap Contributors, CC-BY-SA"
TileSource="http://{c}.tile3.opencyclemap.org/landscape/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="MapQuest OSM" Description="MapQuest OSM - © {y} MapQuest &amp; OpenStreetMap Contributors"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"/>
<!--
TileLayers with OpenStreetMap data.
-->
<map:TileLayer SourceName="OpenStreetMap"
Description="Maps © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"
MaxZoomLevel="19"/>
<map:TileLayer SourceName="Thunderforest OpenCycleMap"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Landscape"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Outdoors"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Transport"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/transport/{z}/{x}/{y}.png"/>
<map:TileLayer SourceName="Thunderforest Transport Dark"
Description="Maps © [Thunderforest](http://www.thunderforest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://{c}.tile.thunderforest.com/transport-dark/{z}/{x}/{y}.png"
Background="Black" Foreground="White"/>
<map:TileLayer SourceName="MapQuest OpenStreetMap"
Description="Maps © [MapQuest](http://www.mapquest.com/), Data © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://otile{n}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"
MaxZoomLevel="19"/>
<map:TileLayer SourceName="Seamarks"
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png"
MinZoomLevel="10" MaxZoomLevel="18"/>
<!-- Tiles from WORLD OSM WMS, a Web Map Service based on OpenStreetMap data -->
<!--<map:TileLayer SourceName="WORLD OSM WMS" Description="WORLD OSM WMS (http://wiki.openstreetmap.org/wiki/OSM-WMS-EUROPE)"
<!--
Bing Maps TileLayers with tile URLs retrieved from the Imagery Metadata Service
(see http://msdn.microsoft.com/en-us/library/ff701716.aspx).
A Bing Maps API Key (see http://msdn.microsoft.com/en-us/library/ff428642.aspx) is required
for using these layers and must be assigned to the static BingMapsTileLayer.ApiKey property.
-->
<map:BingMapsTileLayer SourceName="Bing Maps Road"
Description="© [Microsoft Corporation](http://www.bing.com/maps/)"
Mode="Road" MaxZoomLevel="19"/>
<map:BingMapsTileLayer SourceName="Bing Maps Aerial"
Description="© [Microsoft Corporation](http://www.bing.com/maps/)"
Mode="Aerial" MaxZoomLevel="19" Foreground="White" Background="Black"/>
<map:BingMapsTileLayer SourceName="Bing Maps Hybrid"
Description="© [Microsoft Corporation](http://www.bing.com/maps/)"
Mode="AerialWithLabels" MaxZoomLevel="19" Foreground="White" Background="Black"/>
<!--
A TileLayer for World OSM WMS, a Web Map Service based on OpenStreetMap data.
-->
<!--<map:TileLayer SourceName="World OSM WMS"
Description="[World OSM WMS](http://www.osm-wms.de/) © [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="http://129.206.228.72/cached/osm?SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetMap&amp;LAYERS=osm_auto:all&amp;STYLES=&amp;SRS=EPSG:900913&amp;BBOX={W},{S},{E},{N}&amp;WIDTH=256&amp;HEIGHT=256&amp;FORMAT=image/png"/>-->
<!-- Note: The providers of the following TileLayers do not allow access to their
map content without using their APIs (i.e. Google Maps API or Bing Maps API).
Hence the declarations shown below are for demonstration purpose only. -->
<!--<map:TileLayer SourceName="Google Maps" Description="Google Maps - © {y} Google"
TileSource="http://mt{i}.google.com/vt/x={x}&amp;y={y}&amp;z={z}" MaxZoomLevel="20"/>
<map:TileLayer SourceName="Google Images" Description="Google Maps - © {y} Google" Background="#FF3F3F3F" Foreground="White"
TileSource="http://khm{i}.google.com/kh/v=144&amp;x={x}&amp;y={y}&amp;z={z}" MaxZoomLevel="20"/>
<map:TileLayer SourceName="Bing Maps" Description="Bing Maps - © {y} Microsoft Corporation"
TileSource="http://ecn.t{i}.tiles.virtualearth.net/tiles/r{q}.png?g=0&amp;stl=h" MinZoomLevel="1" MaxZoomLevel="19"/>
<map:TileLayer SourceName="Bing Images" Description="Bing Maps - © {y} Microsoft Corporation" Background="#FF3F3F3F" Foreground="White"
TileSource="http://ecn.t{i}.tiles.virtualearth.net/tiles/a{q}.jpeg?g=0" MinZoomLevel="1" MaxZoomLevel="19"/>
<map:TileLayer SourceName="Bing Hybrid" Description="Bing Maps - © {y} Microsoft Corporation" Background="#FF3F3F3F" Foreground="White"
TileSource="http://ecn.t{i}.tiles.virtualearth.net/tiles/h{q}.jpeg?g=0&amp;stl=h" MinZoomLevel="1" MaxZoomLevel="19"/>-->
<!-- The following TileLayer uses an ImageTileSource, which bypasses caching of map tile images -->
<!--<map:TileLayer SourceName="OSM Uncached" Description="© {y} OpenStreetMap Contributors, CC-BY-SA">
<!--
A TileLayer that uses an ImageTileSource, which bypasses caching of map tile images
-->
<!--<map:TileLayer SourceName="OSM Uncached"
Description="© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)">
<map:ImageTileSource IsAsync="True" UriFormat="http://{c}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
</map:TileLayer>-->
<!-- The following TileLayer demonstrates how to access local tile image files (from ImageFileCache here) -->
<!--<map:TileLayer SourceName="OSM Local Files" Description="© {y} OpenStreetMap Contributors, CC-BY-SA"
<!--
A TileLayer that demonstrates how to access local tile image files (from ImageFileCache here)
-->
<!--<map:TileLayer SourceName="OSM Local Files"
Description="© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
TileSource="file:///C:/ProgramData/MapControl/TileCache/OpenStreetMap/{z}/{x}/{y}.png"/>-->
</map:TileLayerCollection>
<map:TileLayer x:Key="SeamarksTileLayer" SourceName="Seamarks" Description="© {y} OpenSeaMap Contributors, CC-BY-SA"
TileSource="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" MinZoomLevel="10" MaxZoomLevel="18"/>
<CollectionViewSource x:Key="TileLayersViewSource" Source="{StaticResource TileLayers}"/>
<local:LocationToVisibilityConverter x:Key="LocationToVisibilityConverter"/>
<DataTemplate x:Key="PolylineItemTemplate">
<map:MapPolyline Locations="{Binding Locations}" Stroke="Red" StrokeThickness="3"/>
@ -66,6 +93,7 @@
</Style>
<Style x:Key="PointItemStyle" TargetType="map:MapItem">
<Setter Property="map:MapPanel.Location" Value="{Binding Location}"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="map:MapItem">
@ -146,23 +174,22 @@
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<map:Map x:Name="map" Margin="2" Center="{Binding MapCenter}" ZoomLevel="11" MaxZoomLevel="20"
TileLayer="{Binding Source={StaticResource TileLayersViewSource}, Path=CurrentItem}"
<map:Map x:Name="map" Center="{Binding MapCenter}" ZoomLevel="11" MaxZoomLevel="20"
MouseLeftButtonDown="MapMouseLeftButtonDown" MouseRightButtonDown="MapMouseRightButtonDown"
MouseMove="MapMouseMove" MouseLeave="MapMouseLeave"
ManipulationInertiaStarting="MapManipulationInertiaStarting">
<!-- experimental WMS map layers -->
<!--<map:MapImageLayer Opacity="0.5"
UriFormat="http://watzmann-geog.urz.uni-heidelberg.de/cached/osm?SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetMap&amp;LAYERS=osm_auto:all&amp;STYLES=&amp;SRS=EPSG:900913&amp;BBOX={W},{S},{E},{N}&amp;WIDTH={X}&amp;HEIGHT={Y}&amp;FORMAT=image/png"/>-->
<!--<map:MapImageLayer Opacity="0.5"
UriFormat="http://ows.terrestris.de/osm/service?SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetMap&amp;LAYERS=OSM-WMS&amp;STYLES=&amp;SRS=EPSG:900913&amp;BBOX={W},{S},{E},{N}&amp;WIDTH={X}&amp;HEIGHT={Y}&amp;FORMAT=image/png"/>-->
<!--<map:MapImageLayer
UriFormat="http://129.206.228.72/cached/osm?SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetMap&amp;LAYERS=osm_auto:all&amp;STYLES=&amp;SRS=EPSG:900913&amp;BBOX={W},{S},{E},{N}&amp;WIDTH={X}&amp;HEIGHT={Y}&amp;FORMAT=image/png"/>-->
<!--<map:MapImageLayer
UriFormat="http://ows.terrestris.de/osm/service?SERVICE=WMS&amp;VERSION=1.1.1&amp;REQUEST=GetMap&amp;LAYERS=OSM-WMS&amp;STYLES=&amp;SRS=EPSG:900913&amp;BBOX={W},{S},{E},{N}&amp;WIDTH={X}&amp;HEIGHT={Y}&amp;FORMAT=image/png"/>-->
<map:MapImage x:Name="mapImage" South="53.54031" North="53.74871" West="8.08594" East="8.43750"
Source="10_535_330.jpg" Opacity="0.5"/>
<map:MapGraticule Opacity="0.6"/>
<map:MapScale Margin="4" Opacity="0.8"/>
<map:MapScale Margin="4" Opacity="0.8" HorizontalAlignment="Left"/>
<!-- use ItemTemplate or ItemContainerStyle alternatively -->
<map:MapItemsControl ItemsSource="{Binding Polylines}"
@ -193,10 +220,10 @@
<EllipseGeometry RadiusX="1852" RadiusY="1852" Transform="{Binding ScaleTransform, ElementName=map}"/>
</Path.Data>
</Path>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="4" FontSize="10"
Text="{Binding TileLayer.Description, ElementName=map}"/>
</map:Map>
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#7FFFFFFF">
<TextBlock x:Name="mapLegend" Margin="2" FontSize="10"/>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
@ -223,8 +250,19 @@
</StackPanel>
<CheckBox ToolTip="Seamarks Overlay" Margin="7" VerticalAlignment="Bottom" Content="Seamarks"
Checked="SeamarksChecked" Unchecked="SeamarksUnchecked"/>
<ComboBox ToolTip="Tile Layer" Margin="5" VerticalAlignment="Bottom" DisplayMemberPath="SourceName"
SelectedIndex="0" ItemsSource="{Binding Source={StaticResource TileLayersViewSource}}"/>
<ComboBox x:Name="tileLayerComboBox" ToolTip="Tile Layer" Margin="5" VerticalAlignment="Bottom"
SelectionChanged="TileLayerSelectionChanged">
<ComboBoxItem Tag="OpenStreetMap">OpenStreetMap</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest OpenCycleMap">OpenCycleMap</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Landscape">Landscape</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Outdoors">Outdoors</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Transport">Transport</ComboBoxItem>
<ComboBoxItem Tag="Thunderforest Transport Dark">Transport Dark</ComboBoxItem>
<ComboBoxItem Tag="MapQuest OpenStreetMap">MapQuest Open</ComboBoxItem>
<!--<ComboBoxItem Tag="Bing Maps Road">Bing Maps Road</ComboBoxItem>
<ComboBoxItem Tag="Bing Maps Aerial">Bing Maps Aerial</ComboBoxItem>
<ComboBoxItem Tag="Bing Maps Hybrid">Bing Maps Hybrid</ComboBoxItem>-->
</ComboBox>
</StackPanel>
</Grid>
</Grid>

View file

@ -2,6 +2,7 @@
using System.Globalization;
using System.Runtime.Caching;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Caching;
using MapControl;
@ -10,24 +11,34 @@ namespace WpfApplication
{
public partial class MainWindow : Window
{
private TileLayerCollection tileLayers;
public MainWindow()
{
switch (Properties.Settings.Default.TileCache)
{
case "MemoryCache":
TileImageLoader.Cache = MemoryCache.Default;
TileImageLoader.Cache = MemoryCache.Default; // this is the default value of the TileImageLoader.Cache property
break;
case "ImageFileCache":
TileImageLoader.Cache = new ImageFileCache(TileImageLoader.DefaultCacheName, TileImageLoader.DefaultCacheDirectory);
break;
case "FileDbCache":
TileImageLoader.Cache = new FileDbCache(TileImageLoader.DefaultCacheName, TileImageLoader.DefaultCacheDirectory);
break;
case "ImageFileCache":
TileImageLoader.Cache = new ImageFileCache(TileImageLoader.DefaultCacheName, TileImageLoader.DefaultCacheDirectory);
case "None":
TileImageLoader.Cache = null;
break;
default:
break;
}
//BingMapsTileLayer.ApiKey = ...
InitializeComponent();
tileLayers = (TileLayerCollection)Resources["TileLayers"];
tileLayerComboBox.SelectedIndex = 0;
}
private void MapMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
@ -90,14 +101,24 @@ namespace WpfApplication
e.Handled = true;
}
private void TileLayerSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = (ComboBoxItem)tileLayerComboBox.SelectedItem;
map.TileLayer = tileLayers[(string)selectedItem.Tag];
mapLegend.Inlines.Clear();
mapLegend.Inlines.AddRange(map.TileLayer.DescriptionInlines);
}
private void SeamarksChecked(object sender, RoutedEventArgs e)
{
map.TileLayers.Add((TileLayer)Resources["SeamarksTileLayer"]);
map.TileLayers.Add(tileLayers["Seamarks"]);
}
private void SeamarksUnchecked(object sender, RoutedEventArgs e)
{
map.TileLayers.Remove((TileLayer)Resources["SeamarksTileLayer"]);
map.TileLayers.Remove(tileLayers["Seamarks"]);
}
}
}

View file

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