diff --git a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs index 4545fab0..969bf3c2 100644 --- a/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs +++ b/Caching/FileDbCache.WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("3.2.0")] -[assembly: AssemblyFileVersion("3.2.0")] +[assembly: AssemblyVersion("3.3.0")] +[assembly: AssemblyFileVersion("3.3.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs b/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs index 6402489d..cc33c8ea 100644 --- a/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs +++ b/Caching/FileDbCache.WinRT/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("3.2.0")] -[assembly: AssemblyFileVersion("3.2.0")] +[assembly: AssemblyVersion("3.3.0")] +[assembly: AssemblyFileVersion("3.3.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs b/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs index d0cdf11b..983860e4 100644 --- a/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs +++ b/Caching/ImageFileCache.WPF/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("3.2.0")] -[assembly: AssemblyFileVersion("3.2.0")] +[assembly: AssemblyVersion("3.3.0")] +[assembly: AssemblyFileVersion("3.3.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs b/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs index 0e35675d..7835e5a2 100644 --- a/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs +++ b/Caching/ImageFileCache.WinRT/Properties/AssemblyInfo.cs @@ -7,8 +7,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("3.2.0")] -[assembly: AssemblyFileVersion("3.2.0")] +[assembly: AssemblyVersion("3.3.0")] +[assembly: AssemblyFileVersion("3.3.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/ImageTileSource.Silverlight.WinRT.cs b/MapControl/ImageTileSource.Silverlight.WinRT.cs index 6c14b103..824d0a5f 100644 --- a/MapControl/ImageTileSource.Silverlight.WinRT.cs +++ b/MapControl/ImageTileSource.Silverlight.WinRT.cs @@ -13,9 +13,9 @@ using System.Windows.Media.Imaging; namespace MapControl { /// - /// Provides the image of a map tile. ImageTileSource bypasses image - /// downloading in TileImageLoader. By overriding the LoadImage method, - /// an application can provide tile images from an arbitrary source. + /// Provides the image of a map tile. + /// ImageTileSource bypasses image downloading and optional caching in TileImageLoader. + /// By overriding the LoadImage method, an application can provide tile images from an arbitrary source. /// public class ImageTileSource : TileSource { diff --git a/MapControl/MapTileLayer.cs b/MapControl/MapTileLayer.cs index 5ea442c2..4368d0a2 100644 --- a/MapControl/MapTileLayer.cs +++ b/MapControl/MapTileLayer.cs @@ -55,7 +55,7 @@ namespace MapControl public static readonly DependencyProperty TileSourceProperty = DependencyProperty.Register( nameof(TileSource), typeof(TileSource), typeof(MapTileLayer), - new PropertyMetadata(null, (o, e) => ((MapTileLayer)o).ResetTiles())); + new PropertyMetadata(null, (o, e) => ((MapTileLayer)o).TileSourcePropertyChanged())); public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register( nameof(SourceName), typeof(string), typeof(MapTileLayer), new PropertyMetadata(null)); @@ -125,7 +125,7 @@ namespace MapControl } /// - /// Name of the TileSource. Used as key in a TileLayerCollection and as component of a tile cache key. + /// Name of the TileSource. Used as component of a tile cache key. /// public string SourceName { @@ -134,8 +134,7 @@ namespace MapControl } /// - /// Description of the MapTileLayer. - /// Used to display copyright information on top of the map. + /// Description of the MapTileLayer. Used to display copyright information on top of the map. /// public string Description { @@ -198,8 +197,7 @@ namespace MapControl } /// - /// Optional background brush. - /// Sets MapBase.Background if not null and the MapTileLayer is the base map layer. + /// Optional background brush. Sets MapBase.Background if not null and the MapTileLayer is the base map layer. /// public Brush MapBackground { @@ -208,8 +206,7 @@ namespace MapControl } /// - /// Optional foreground brush. - /// Sets MapBase.Foreground if not null and the MapTileLayer is the base map layer. + /// Optional foreground brush. Sets MapBase.Foreground if not null and the MapTileLayer is the base map layer. /// public Brush MapForeground { @@ -287,7 +284,16 @@ namespace MapControl else { TileGrid = null; - ResetTiles(); + UpdateTiles(); + } + } + + private void TileSourcePropertyChanged() + { + if (TileGrid != null) + { + Tiles.Clear(); + UpdateTiles(); } } @@ -295,8 +301,7 @@ namespace MapControl { if (TileGrid == null || e.ProjectionChanged || Math.Abs(e.LongitudeOffset) > 180d) { - // update immediately when map projection has changed or map center has moved across 180° longitude - UpdateTileGrid(); + UpdateTileGrid(); // update immediately when projection has changed or center has moved across 180° longitude } else { @@ -314,9 +319,8 @@ namespace MapControl } } - private Point GetTileCenter(double tileScale) + private Point GetTileCenter(double tileScale) // map center in tile index coordinates { - // map center in tile index coordinates return new Point( tileScale * (0.5 + parentMap.Center.Longitude / 360d), tileScale * (0.5 - WebMercatorProjection.LatitudeToY(parentMap.Center.Latitude) / 360d)); @@ -354,27 +358,7 @@ namespace MapControl MatrixEx.TranslateScaleRotateTranslate(tileOrigin, scale, parentMap.Heading, viewCenter); } - private void ResetTiles() - { - Tiles.Clear(); - UpdateTiles(); - } - private void UpdateTiles() - { - SelectTiles(); - - Children.Clear(); - - foreach (var tile in Tiles) - { - Children.Add(tile.Image); - } - - TileImageLoader.LoadTiles(this); - } - - private void SelectTiles() { var newTiles = new List(); @@ -406,8 +390,7 @@ namespace MapControl if (equivalentTile != null) { - // do not animate to avoid flicker when crossing 180° - tile.SetImage(equivalentTile.Image.Source, false); + tile.SetImage(equivalentTile.Image.Source, false); // do not animate to avoid flicker when crossing 180° longitude } } @@ -418,6 +401,15 @@ namespace MapControl } Tiles = newTiles; + + Children.Clear(); + + foreach (var tile in Tiles) + { + Children.Add(tile.Image); + } + + TileImageLoader.LoadTiles(this); } } } diff --git a/MapControl/Properties/AssemblyInfo.cs b/MapControl/Properties/AssemblyInfo.cs index 91326449..c9a05a9e 100644 --- a/MapControl/Properties/AssemblyInfo.cs +++ b/MapControl/Properties/AssemblyInfo.cs @@ -14,8 +14,8 @@ using System.Windows; [assembly: AssemblyCompany("Clemens Fischer")] [assembly: AssemblyCopyright("© 2017 Clemens Fischer")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("3.2.0")] -[assembly: AssemblyFileVersion("3.2.0")] +[assembly: AssemblyVersion("3.3.0")] +[assembly: AssemblyFileVersion("3.3.0")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] diff --git a/MapControl/TileImageLoader.Silverlight.cs b/MapControl/TileImageLoader.Silverlight.cs index aafc4ec1..9c613dc9 100644 --- a/MapControl/TileImageLoader.Silverlight.cs +++ b/MapControl/TileImageLoader.Silverlight.cs @@ -13,7 +13,7 @@ namespace MapControl /// /// Loads map tile images. /// - internal class TileImageLoader : ITileImageLoader + public class TileImageLoader : ITileImageLoader { public void LoadTiles(MapTileLayer tileLayer) { diff --git a/MapControl/TileImageLoader.WPF.cs b/MapControl/TileImageLoader.WPF.cs index a34e06d0..f214efcb 100644 --- a/MapControl/TileImageLoader.WPF.cs +++ b/MapControl/TileImageLoader.WPF.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -69,11 +68,11 @@ namespace MapControl { pendingTiles.Clear(); - var tileStack = tileLayer.Tiles.Where(t => t.Pending).Reverse().ToArray(); + var tiles = tileLayer.Tiles.Where(t => t.Pending); - if (tileStack.Length > 0) + if (tiles.Any()) { - pendingTiles.PushRange(tileStack); + pendingTiles.PushRange(tiles.Reverse().ToArray()); var tileSource = tileLayer.TileSource; var sourceName = tileLayer.SourceName; diff --git a/MapControl/TileImageLoader.WinRT.cs b/MapControl/TileImageLoader.WinRT.cs index 0b755182..712cab76 100644 --- a/MapControl/TileImageLoader.WinRT.cs +++ b/MapControl/TileImageLoader.WinRT.cs @@ -64,21 +64,20 @@ namespace MapControl { pendingTiles.Clear(); - var tileSource = tileLayer.TileSource; - var imageTileSource = tileSource as ImageTileSource; var tiles = tileLayer.Tiles.Where(t => t.Pending); - if (imageTileSource != null) + if (tiles.Any()) { - LoadTiles(imageTileSource, tiles); - } - else - { - var tileStack = tiles.Reverse().ToArray(); + var tileSource = tileLayer.TileSource; + var imageTileSource = tileSource as ImageTileSource; - if (tileStack.Length > 0) + if (imageTileSource != null) { - pendingTiles.PushRange(tileStack); + LoadTiles(tiles, imageTileSource); + } + else + { + pendingTiles.PushRange(tiles.Reverse().ToArray()); var sourceName = tileLayer.SourceName; var maxDownloads = tileLayer.MaxParallelDownloads; @@ -98,7 +97,7 @@ namespace MapControl } } - private void LoadTiles(ImageTileSource tileSource, IEnumerable tiles) + private void LoadTiles(IEnumerable tiles, ImageTileSource tileSource) { foreach (var tile in tiles) { @@ -134,7 +133,15 @@ namespace MapControl if (uri != null) { - if (Cache == null || sourceName == null) + if (!uri.IsAbsoluteUri) + { + await LoadImageFromFile(tile, uri.OriginalString); + } + else if (uri.Scheme == "file") + { + await LoadImageFromFile(tile, uri.LocalPath); + } + else if (Cache == null || sourceName == null) { await DownloadImage(tile, uri, null); } @@ -186,7 +193,14 @@ namespace MapControl { if (response.IsSuccessStatusCode) { - return await LoadImageFromHttpResponse(response, tile, cacheKey); + string tileInfo; + + if (!response.Headers.TryGetValue("X-VE-Tile-Info", out tileInfo) || tileInfo != "no-tile") // set by Bing Maps + { + await LoadImageFromHttpResponse(response, tile, cacheKey); + } + + return true; } Debug.WriteLine("{0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase); @@ -200,15 +214,8 @@ namespace MapControl return false; } - private async Task LoadImageFromHttpResponse(HttpResponseMessage response, Tile tile, string cacheKey) + private async Task LoadImageFromHttpResponse(HttpResponseMessage response, Tile tile, string cacheKey) { - string tileInfo; - - if (response.Headers.TryGetValue("X-VE-Tile-Info", out tileInfo) && tileInfo == "no-tile") // set by Bing Maps - { - return true; - } - using (var stream = new InMemoryRandomAccessStream()) { using (var content = response.Content) @@ -219,9 +226,9 @@ namespace MapControl await stream.FlushAsync(); stream.Seek(0); - var loaded = await LoadImageFromStream(tile, stream); + await LoadImageFromStream(tile, stream); - if (loaded && cacheKey != null) + if (cacheKey != null) { var buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size); @@ -242,14 +249,29 @@ namespace MapControl await Cache.SetAsync(cacheKey, buffer, DateTime.UtcNow.Add(expiration)); } - - return loaded; } } - private async Task LoadImageFromStream(Tile tile, IRandomAccessStream stream) + private async Task LoadImageFromFile(Tile tile, string path) { - var tcs = new TaskCompletionSource(); + try + { + var file = await StorageFile.GetFileFromPathAsync(path); + + using (var stream = await file.OpenReadAsync()) + { + await LoadImageFromStream(tile, stream); + } + } + catch (Exception ex) + { + Debug.WriteLine("{0}: {1}", path, ex.Message); + } + } + + private async Task LoadImageFromStream(Tile tile, IRandomAccessStream stream) + { + var tcs = new TaskCompletionSource(); await tile.Image.Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () => { @@ -258,16 +280,16 @@ namespace MapControl var image = new BitmapImage(); await image.SetSourceAsync(stream); tile.SetImage(image, true, false); - tcs.SetResult(true); + + tcs.SetResult(null); } catch (Exception ex) { - Debug.WriteLine("{0}/{1}/{2}: {3}", tile.ZoomLevel, tile.XIndex, tile.Y, ex.Message); - tcs.SetResult(false); + tcs.SetException(ex); } }); - return await tcs.Task; + await tcs.Task; } } } diff --git a/MapControl/WinRT/MapControl.WinRT.csproj b/MapControl/WinRT/MapControl.WinRT.csproj index 02f67beb..5b5a5c4f 100644 --- a/MapControl/WinRT/MapControl.WinRT.csproj +++ b/MapControl/WinRT/MapControl.WinRT.csproj @@ -26,6 +26,7 @@ TRACE;DEBUG;NETFX_CORE prompt 4 + true none @@ -34,6 +35,7 @@ TRACE;NETFX_CORE prompt 4 + true @@ -212,7 +214,7 @@ - copy "$(ProjectDir)MapControl.WinRT.xr.xml" "$(TargetDir)" + copy "$(ProjectDir)$(TargetName).xr.xml" "$(TargetDir)$(TargetName)\"