private static void UpdateGraphicsAndRenderer(KmlGraphicsLayer layer, UniqueValueRenderer renderer, string key) { foreach (var graphic in layer.Graphics) { var f = (PlacemarkDescriptor)graphic.GetValue(FeaturePlacemarkerDescriptorProperty); if (f.Symbol.style.IconHref != null && f.Symbol.style.IconHref.ToLower() == key) { graphic.Symbol = PointSymbolDescriptor.GetDefaultSymbol(); ComputeIconTranslationValues(f.Symbol.style, graphic.Symbol as KmlPlaceMarkerSymbol, ((graphic.Symbol as KmlPlaceMarkerSymbol).Fill as ImageBrush).ImageSource as BitmapImage); string l = null, d = null; GetRendererInfo(f, f.Symbol.style, out l, out d); var info = renderer.Infos.FirstOrDefault(i => i.Label == l); if (info != null) { info.Symbol = graphic.Symbol; } } } }
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { this.InitializationFailure = new ArgumentException(Properties.Resources.KmlLayer_DocumentParsingFailed); } else { // Create graphic features from definitions -- this code requires the UI thread FeatureDefinition fd = (FeatureDefinition)e.Result; // Initialize the layer name with the name info coming from the KML document Name = fd.name; _hasRootContainer = _isRoot && fd.hasRootContainer; // the root container has been collapsed (info needed to generate internal folderIDs) if (_visibleLayerIds != null && !IsInitialized) { // VisibleLayerIds is set --> layer created from a web map --> check that the layer must stay visible (_hasRootContainer is set only after the file has been parsed) if (_hasRootContainer && !_visibleLayerIds.Contains(1)) // FolderIds 1 is the top level folder that may not be visible in SL { Visible = false; _isLoading = false; base.Initialize(); return; } } // Store the parsed styles to be able to pass them to children _context.Styles = fd.styles; // Create ground overlays and add to element layer if (fd.groundOverlays.Any()) { ElementLayer elementLayer = new ElementLayer { ID = Properties.Resources.KmlLayer_GroundOverlaysSublayer }; fd.CreateGroundOverlays(elementLayer, _context.Images, Map); ChildLayers.Add(elementLayer); if (IsInitialized) elementLayer.Initialize(); // should be done by the group layer (to remove when Bug#2718 is fixed) } // Create graphics and add to graphics layer if (fd.placemarks.Any()) { KmlGraphicsLayer kmlGraphicsLayer = new KmlGraphicsLayer { ID = Properties.Resources.KmlLayer_PlacemarksSublayer, ProjectionService = ProjectionService, IsHidden = _hideChildren }; fd.CreateGraphics(kmlGraphicsLayer, _context.Images); #if !WINDOWS_PHONE kmlGraphicsLayer.MapTip = MapTip; #endif ChildLayers.Add(kmlGraphicsLayer); if (IsInitialized) kmlGraphicsLayer.Initialize(); // should be done by the group layer (to remove when Bug#2718 is fixed) // Setting the Spatial Reference of the KML layer to 4326: if (this.SpatialReference == null) { this.SpatialReference = new Geometry.SpatialReference(4326); } } // Create a sub KML layer for each container foreach (ContainerInfo container in fd.containers) { string fullPath = _fullPath == null ? (container.Name ?? string.Empty) : string.Concat(_fullPath, "/", container.Name); // Note : use internal constructor, so properties such as MapTip, ProxyUrl, VisibleLayers.. are reported to the children var kmlLayer = new KmlLayer(this) { ID = container.Name, Name = container.Name, _fullPath = fullPath, RefreshInterval = TimeSpan.FromSeconds(container.RefreshInterval), VisibleTimeExtent = container.TimeExtent, RegionInfo = container.RegionInfo, _folderId = container.FolderId, _hideChildren = container.HideChildren, IsHidden = _hideChildren }; bool isOk = true; if (string.IsNullOrEmpty(container.Url)) { // Set the visibility of the layer // There are 3 ways to define the visibility of a folder or document, by priority order: // - by the internal VisibleLayerIds property (for the layers inside a web map) // - by the public VisibleLayers property // - by the visibility defined in the KML document kmlLayer.Visible = _visibleLayerIds != null ? _visibleLayerIds.Contains(kmlLayer._folderId) : IsContainerVisible(fullPath, container.Visible); kmlLayer._visibleLayerIds = _visibleLayerIds; // Subfolder : Create a context object and initialize a KmlLayer with it kmlLayer._context = new KmlLayerContext { Element = container.Element, // The XElement that the KML layer has to process Styles = _context.Styles, Images = _context.Images, AtomAuthor = container.AtomAuthor, AtomHref = container.AtomHref }; } else { // NetworkLink : initialize the Url Uri containerUri = GetUri(container.Url, GetBaseUri()); if (containerUri != null) { kmlLayer.Url = containerUri; kmlLayer.ViewRefreshMode = container.ViewRefreshMode; } else isOk = false; // bad url, don't create the child layer // Set the visibility of the layer // For a network link, the internal VisibleLayerIds property is not used. kmlLayer.Visible = IsContainerVisible(fullPath, container.Visible); } if (isOk) { ChildLayers.Add(kmlLayer); if (IsInitialized) kmlLayer.Initialize(); // should be done by the group layer --> to remove later (after or with CR2718) } } // Check that the layer refresh interval is compatible with infos coming from NetworkLinkControl if (fd.networkLinkControl != null) { if (RefreshInterval != TimeSpan.Zero && fd.networkLinkControl.MinRefreshPeriod > 0.0) RefreshInterval = TimeSpan.FromSeconds(Math.Max(RefreshInterval.Seconds, fd.networkLinkControl.MinRefreshPeriod)); } // Set resolution range from the Region/Lods info of the parent SetResolutionRange(); } if (!IsInitialized) base.Initialize(); _isLoading = false; _isLoaded = true; }
/// <summary> /// Creates graphic elements and adds them to the graphics layer. /// </summary> /// <param name="layer">Graphics layer that will have features added to it.</param> /// <param name="images">Dictionary of images coming from kmz content or from previous parsing</param> public void CreateGraphics(KmlGraphicsLayer layer, IDictionary<string, ImageBrush> images) { if (layer == null) return; GraphicCollection graphics = new GraphicCollection(); UniqueValueRenderer renderer = new UniqueValueRenderer(); // dummy renderer used to create the legend items (since creation of the swatches from the symbol is not that obvious) // Process each metadata feature in the list foreach (PlacemarkDescriptor feature in placemarks) { KMLStyle style = feature.Symbol.style; if (style.ZipFile != null) { // Look for the image in the zip file if (style.IconImage == null && !String.IsNullOrEmpty(style.IconHref)) { style.IconImage = GetIconImage(style.ZipFile, style.IconHref.ToLower()); } style.ZipFile.Dispose(); style.ZipFile = null; } //Define handlers upfront so we can unhook from them #if SILVERLIGHT EventHandler<RoutedEventArgs> #else EventHandler #endif imageCompleted = null; #if SILVERLIGHT EventHandler<ExceptionRoutedEventArgs> #else EventHandler<ExceptionEventArgs> #endif imageFailed = null; // If the style has an HREF then it is associated with an image if (style.IconImage == null && !String.IsNullOrEmpty(style.IconHref)) { // If the image is already loaded in the image dictionary, use it if (images.ContainsKey(style.IconHref.ToLower())) style.IconImage = images[style.IconHref.ToLower()]; else { // Get the image using the HREF and store the image in the images dictionary so that if // other features reference it, it is cached style.IconImage = GetIconImage(style.IconHref); if (style.IconImage != null && (style.IconImage as ImageBrush).ImageSource != null) { var bi = (style.IconImage as ImageBrush).ImageSource as BitmapImage; if (bi != null) { imageFailed = (s, e) => { var b = s as BitmapImage; #if SILVERLIGHT if (imageCompleted != null) b.ImageOpened -= imageCompleted; if(imageFailed != null) b.ImageFailed -= imageFailed; #else if (imageCompleted != null) b.DownloadCompleted -= imageCompleted; if (imageFailed != null) b.DownloadFailed -= imageFailed; #endif var key = b.GetValue(BitmapImageKeyProperty) as string; layer.Dispatcher.BeginInvoke((Action)delegate { UpdateGraphicsAndRenderer(layer, renderer, key); }); }; #if SILVERLIGHT bi.ImageFailed += imageFailed; #else bi.DownloadFailed += imageFailed; #endif } } images.Add(style.IconHref.ToLower(), style.IconImage); } } // Create a new graphic from the metadata and construct the symbol using polymorphism Graphic g = new Graphic() { Geometry = feature.Geometry, Symbol = feature.Symbol.CreateSymbol(), TimeExtent = feature.TimeExtent }; g.SetValue(FeaturePlacemarkerDescriptorProperty, feature); // Create legend entry string label; string description; GetRendererInfo(feature, style, out label, out description); if (!string.IsNullOrEmpty(label) && !renderer.Infos.Any(info => info.Label == label)) renderer.Infos.Add(new UniqueValueInfo { Label = label, Description = description, Symbol = g.Symbol }); // Adjust and assign picture marker symbol properties if (g.Geometry is ESRI.ArcGIS.Client.Geometry.MapPoint && g.Symbol is KmlPlaceMarkerSymbol) { try { KmlPlaceMarkerSymbol ms = g.Symbol as KmlPlaceMarkerSymbol; // To match sizing of Google Earth, default size of point images is 40x40 ms.Height = 40; ms.Width = 40; ms.Fill = style.IconImage; ms.IconColor = style.IconColor; // Default to half the pixel size (width and height) if symbol offsets are 0 (supported in wpf and sl3) ImageBrush ib = ms.Fill; BitmapImage bi = ib.ImageSource as BitmapImage; #if SILVERLIGHT if (bi.PixelHeight == 0 || bi.PixelWidth == 0) #else if (bi.IsDownloading) #endif { imageCompleted = (s, e) => { var b = s as BitmapImage; #if SILVERLIGHT if (imageCompleted != null) b.ImageOpened -= imageCompleted; if(imageFailed != null) b.ImageFailed -= imageFailed; #else if (imageCompleted != null) b.DownloadCompleted -= imageCompleted; if (imageFailed != null) b.DownloadFailed -= imageFailed; #endif ComputeIconTranslationValues(style, ms, b); }; #if SILVERLIGHT bi.ImageOpened += imageCompleted; #else bi.DownloadCompleted += imageCompleted; #endif } else { ComputeIconTranslationValues(style, ms, bi); } } catch { g.Symbol = PointSymbolDescriptor.GetDefaultSymbol(); ComputeIconTranslationValues(style, g.Symbol as KmlPlaceMarkerSymbol, ((g.Symbol as KmlPlaceMarkerSymbol).Fill as ImageBrush).ImageSource as BitmapImage); var info = renderer.Infos.FirstOrDefault(i => i.Label == label); if (info != null) { info.Symbol = g.Symbol; } } } // Copy attributes values from metadata to graphic foreach (var attribute in feature.Attributes) { g.Attributes.Add(attribute.Key, attribute.Value); } // If the balloontext property has been assigned a value in the style associated with this // graphic feature, then add it to the attributes collection. if (!String.IsNullOrEmpty(style.BalloonText)) { g.Attributes.Add("balloonText", style.BalloonText); } // Add graphic to graphics layer graphics.Add(g); } layer.Graphics = graphics; // keep the renderer for further usage (when QueryLegendInfos is called) layer.RendererBasedOnStyle = renderer; }
/// <summary> /// Creates graphic elements and adds them to the graphics layer. /// </summary> /// <param name="layer">Graphics layer that will have features added to it.</param> /// <param name="images">Dictionary of images coming from kmz content or from previous parsing</param> public void CreateGraphics(KmlGraphicsLayer layer, IDictionary <string, ImageBrush> images) { if (layer == null) { return; } GraphicCollection graphics = new GraphicCollection(); UniqueValueRenderer renderer = new UniqueValueRenderer(); // dummy renderer used to create the legend items (since creation of the swatches from the symbol is not that obvious) // Process each metadata feature in the list foreach (PlacemarkDescriptor feature in placemarks) { KMLStyle style = feature.Symbol.style; if (style.ZipFile != null) { // Look for the image in the zip file if (style.IconImage == null && !String.IsNullOrEmpty(style.IconHref)) { style.IconImage = GetIconImage(style.ZipFile, style.IconHref.ToLower()); } style.ZipFile.Dispose(); style.ZipFile = null; } //Define handlers upfront so we can unhook from them #if SILVERLIGHT EventHandler <RoutedEventArgs> #else EventHandler #endif imageCompleted = null; #if SILVERLIGHT EventHandler <ExceptionRoutedEventArgs> #else EventHandler <ExceptionEventArgs> #endif imageFailed = null; // If the style has an HREF then it is associated with an image if (style.IconImage == null && !String.IsNullOrEmpty(style.IconHref)) { // If the image is already loaded in the image dictionary, use it if (images.ContainsKey(style.IconHref.ToLower())) { style.IconImage = images[style.IconHref.ToLower()]; } else { // Get the image using the HREF and store the image in the images dictionary so that if // other features reference it, it is cached style.IconImage = GetIconImage(style.IconHref); if (style.IconImage != null && (style.IconImage as ImageBrush).ImageSource != null) { var bi = (style.IconImage as ImageBrush).ImageSource as BitmapImage; if (bi != null) { imageFailed = (s, e) => { var b = s as BitmapImage; #if SILVERLIGHT if (imageCompleted != null) { b.ImageOpened -= imageCompleted; } if (imageFailed != null) { b.ImageFailed -= imageFailed; } #else if (imageCompleted != null) { b.DownloadCompleted -= imageCompleted; } if (imageFailed != null) { b.DownloadFailed -= imageFailed; } #endif var key = b.GetValue(BitmapImageKeyProperty) as string; layer.Dispatcher.BeginInvoke((Action) delegate { UpdateGraphicsAndRenderer(layer, renderer, key); }); }; #if SILVERLIGHT bi.ImageFailed += imageFailed; #else bi.DownloadFailed += imageFailed; #endif } } images.Add(style.IconHref.ToLower(), style.IconImage); } } // Create a new graphic from the metadata and construct the symbol using polymorphism Graphic g = new Graphic() { Geometry = feature.Geometry, Symbol = feature.Symbol.CreateSymbol(), TimeExtent = feature.TimeExtent }; g.SetValue(FeaturePlacemarkerDescriptorProperty, feature); // Create legend entry string label; string description; GetRendererInfo(feature, style, out label, out description); if (!string.IsNullOrEmpty(label) && !renderer.Infos.Any(info => info.Label == label)) { renderer.Infos.Add(new UniqueValueInfo { Label = label, Description = description, Symbol = g.Symbol }); } // Adjust and assign picture marker symbol properties if (g.Geometry is ESRI.ArcGIS.Client.Geometry.MapPoint && g.Symbol is KmlPlaceMarkerSymbol) { try { KmlPlaceMarkerSymbol ms = g.Symbol as KmlPlaceMarkerSymbol; // To match sizing of Google Earth, default size of point images is 40x40 ms.Height = 40; ms.Width = 40; ms.Fill = style.IconImage; ms.IconColor = style.IconColor; // Default to half the pixel size (width and height) if symbol offsets are 0 (supported in wpf and sl3) ImageBrush ib = ms.Fill; BitmapImage bi = ib.ImageSource as BitmapImage; #if SILVERLIGHT if (bi.PixelHeight == 0 || bi.PixelWidth == 0) #else if (bi.IsDownloading) #endif { imageCompleted = (s, e) => { var b = s as BitmapImage; #if SILVERLIGHT if (imageCompleted != null) { b.ImageOpened -= imageCompleted; } if (imageFailed != null) { b.ImageFailed -= imageFailed; } #else if (imageCompleted != null) { b.DownloadCompleted -= imageCompleted; } if (imageFailed != null) { b.DownloadFailed -= imageFailed; } #endif ComputeIconTranslationValues(style, ms, b); }; #if SILVERLIGHT bi.ImageOpened += imageCompleted; #else bi.DownloadCompleted += imageCompleted; #endif } else { ComputeIconTranslationValues(style, ms, bi); } } catch { g.Symbol = PointSymbolDescriptor.GetDefaultSymbol(); ComputeIconTranslationValues(style, g.Symbol as KmlPlaceMarkerSymbol, ((g.Symbol as KmlPlaceMarkerSymbol).Fill as ImageBrush).ImageSource as BitmapImage); var info = renderer.Infos.FirstOrDefault(i => i.Label == label); if (info != null) { info.Symbol = g.Symbol; } } } // Copy attributes values from metadata to graphic foreach (var attribute in feature.Attributes) { g.Attributes.Add(attribute.Key, attribute.Value); } // If the balloontext property has been assigned a value in the style associated with this // graphic feature, then add it to the attributes collection. if (!String.IsNullOrEmpty(style.BalloonText)) { g.Attributes.Add("balloonText", style.BalloonText); } // Add graphic to graphics layer graphics.Add(g); } layer.Graphics = graphics; // keep the renderer for further usage (when QueryLegendInfos is called) layer.RendererBasedOnStyle = renderer; }
/// <summary> /// Creates graphic elements and adds them to the graphics layer. /// </summary> /// <param name="layer">Graphics layer that will have features added to it.</param> /// <param name="images">Dictionary of images coming from kmz content or from previous parsing</param> public void CreateGraphics(KmlGraphicsLayer layer, IDictionary<string, ImageBrush> images) { if (layer == null) return; GraphicCollection graphics = new GraphicCollection(); UniqueValueRenderer renderer = new UniqueValueRenderer(); // dummy renderer used to create the legend items (since creation of the swatches from the symbol is not that obvious) // Process each metadata feature in the list foreach (PlacemarkDescriptor feature in placemarks) { KMLStyle style = feature.Symbol.style; if (style.ZipFile != null) { // Look for the image in the zip file if (style.IconImage == null && !String.IsNullOrEmpty(style.IconHref)) { style.IconImage = GetIconImage(style.ZipFile, style.IconHref.ToLower()); } style.ZipFile.Dispose(); style.ZipFile = null; } // If the style has an HREF then it is associated with an image if (style.IconImage == null && !String.IsNullOrEmpty(style.IconHref)) { // If the image is already loaded in the image dictionary, use it if (images.ContainsKey(style.IconHref.ToLower())) style.IconImage = images[style.IconHref.ToLower()]; else { // Get the image using the HREF and store the image in the images dictionary so that if // other features reference it, it is cached style.IconImage = GetIconImage(style.IconHref); images.Add(style.IconHref.ToLower(), style.IconImage); } } // Create a new graphic from the metadata and construct the symbol using polymorphism Graphic g = new Graphic() { Geometry = feature.Geometry, Symbol = feature.Symbol.CreateSymbol() }; // Create legend entry string label = null; string description = null; if (string.IsNullOrEmpty(style.StyleId)) { //if the feature is not using a shared style -> create an entry by graphic with the name as ident if (feature.Attributes.ContainsKey("name")) label = feature.Attributes["name"].ToString(); if (feature.Attributes.ContainsKey("description")) description = feature.Attributes["description"].ToString(); } else { //if the feature is using a shared style -> create an entry for the style label = style.StyleId; } if (!string.IsNullOrEmpty(label) && !renderer.Infos.Any(info => info.Label == label)) renderer.Infos.Add(new UniqueValueInfo { Label = label, Description = description, Symbol = g.Symbol }); // Adjust and assign picture marker symbol properties if (g.Geometry is ESRI.ArcGIS.Client.Geometry.MapPoint && g.Symbol is KmlPlaceMarkerSymbol) { try { #if SILVERLIGHT string ext = style.IconHref.Substring(style.IconHref.LastIndexOf(".")).ToLower(); switch (ext) { case ".jpg": case ".jpeg": case ".png": break; default: throw new System.Exception(string.Format(Properties.Resources.FeatureDefinition_ImageTypeNotSupported, ext)); } #endif KmlPlaceMarkerSymbol ms = g.Symbol as KmlPlaceMarkerSymbol; // To match sizing of Google Earth, default size of point images is 40x40 ms.Height = 40; ms.Width = 40; ms.Fill = style.IconImage as ImageBrush; // Default to half the pixel size (width and height) if symbol offsets are 0 (supported in wpf and sl3) ImageBrush ib = ms.Fill; BitmapImage bi = ib.ImageSource as BitmapImage; #if SILVERLIGHT if (bi.PixelHeight == 0 || bi.PixelWidth == 0) { EventHandler<RoutedEventArgs> completed = null; completed = (s, e) => { bi.ImageOpened -= completed; ComputeIconTranslationValues(style, ms, bi); }; bi.ImageOpened += completed; } #else if (bi.IsDownloading) { EventHandler completed = null; completed = (s, e) => { bi.DownloadCompleted -= completed; ComputeIconTranslationValues(style, ms, bi); }; bi.DownloadCompleted += completed; } #endif else { ComputeIconTranslationValues(style, ms, bi); } } catch { g.Symbol = new SimpleMarkerSymbol(); } } // Copy attributes values from metadata to graphic foreach (var attribute in feature.Attributes) { g.Attributes.Add(attribute.Key, attribute.Value); } // If the balloontext property has been assigned a value in the style associated with this // graphic feature, then add it to the attributes collection. if (!String.IsNullOrEmpty(style.BalloonText)) { g.Attributes.Add("balloonText", style.BalloonText); } // Add graphic to graphics layer graphics.Add(g); } layer.Graphics = graphics; // Use the renderer to create the legend itens (asynchronously since creating a swatch from a symbol is asynchronous) renderer.QueryLegendInfos(layerLegendInfo => { layer.LegendInfo = layerLegendInfo;}, null); }