KML GraphicsLayer subclass for allowing legend based on the styles
Inheritance: GraphicsLayer
Example #1
0
 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;
             }
         }
     }
 }
Example #2
0
        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;
        }
		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;
					}
				}
			}
		}
    	/// <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;
		}
Example #5
0
        /// <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);
        }