/// <summary> Initializes a new instance of the <see cref="BingMetaInfo"/> class and sets the imagery set, map version and Bing license key. </summary>
        /// <param name="imagerySet"> Type of map content which is requested. </param>
        /// <param name="mapVersion"> Map version which is to be used. </param>
        /// <param name="key"> Microsoft license key for using Bing. </param>
        public BingMetaInfo(BingImagerySet imagerySet, BingMapVersion mapVersion, string key)
        {
            Key = key;
            var url = $@"http://dev.virtualearth.net/REST/v1/Imagery/Metadata/{Enum.GetName(typeof(BingImagerySet), imagerySet)}?mapVersion={Enum.GetName(typeof(BingMapVersion), mapVersion)}&o=xml&key={key}";

            // parse xml using linq
            XNamespace restNamespace = "http://schemas.microsoft.com/search/local/ws/rest/v1";
            var        metaXml       = XDocument.Load(url);
            var        resourceSets  = from resourceSet in metaXml.Descendants(restNamespace + "ResourceSets")
                                       select new
            {
                Resource = from resource in resourceSet.Descendants(restNamespace + "Resources")
                           select new
                {
                    ImageryMetaData = from meta in resource.Descendants(restNamespace + "ImageryMetadata")
                                      select new
                    {
                        ImagerUrl  = meta.Element(restNamespace + "ImageUrl")?.Value,
                        MinZoom    = Convert.ToInt32(meta.Element(restNamespace + "ZoomMin")?.Value),
                        MaxZoom    = Convert.ToInt32(meta.Element(restNamespace + "ZoomMax")?.Value),
                        SubDomains = from subDomain in meta.Descendants(restNamespace + "ImageUrlSubdomains")
                                     select subDomain.Elements(restNamespace + "string")
                    }
                }
            };

            // initialize properties
            var imageMeta   = resourceSets.First().Resource.First().ImageryMetaData.First();
            var logoUriMeta = from brandLogoUri in metaXml.Descendants(restNamespace + "BrandLogoUri")
                              select new
            {
                URI = brandLogoUri.Value
            };

            LogoUri            = logoUriMeta.First().URI;
            ImageUrl           = imageMeta.ImagerUrl;
            MinZoom            = imageMeta.MinZoom;
            MaxZoom            = imageMeta.MaxZoom;
            ImageUrlSubDomains = imageMeta.SubDomains.First().Select(subDomain => subDomain.Value).ToArray();
        }
 /// <summary> Extension method which adds a Microsoft Bing layer to the map. </summary>
 /// <param name="wpfMap"> The map to add the layer to. </param>
 /// <param name="name"> The name of the layer. </param>
 /// <param name="idx"> The index of the layer in the layer hierarchy. </param>
 /// <param name="bingKey"> The Microsoft Bing key to use. </param>
 /// <param name="set"> The imagery set to be used. </param>
 /// <param name="version"> The Microsoft Bing version. </param>
 /// <param name="isBaseMapLayer"> Specifies if the added layer should act as a base layer. </param>
 /// <param name="opacity"> The initial opacity of the layer. </param>
 /// <param name="icon"> The icon of the layer used within the layer gadget. </param>
 public static void AddBingLayer(this WpfMap wpfMap, string name, int idx, string bingKey, BingImagerySet set, BingMapVersion version, bool isBaseMapLayer, double opacity, BitmapImage icon)
 {
     AddBingLayer(wpfMap, name, idx, bingKey, set, version, isBaseMapLayer, opacity, icon, wpfMap.CopyrightImagePanel);
 }
        /// <summary> Extension method which adds a Microsoft Bing layer to the map. </summary>
        /// <param name="wpfMap"> The map to add the layer to. </param>
        /// <param name="name"> The name of the layer. </param>
        /// <param name="idx"> The index of the layer in the layer hierarchy. </param>
        /// <param name="bingKey"> The Microsoft Bing key to use. </param>
        /// <param name="set"> The imagery set to be used. </param>
        /// <param name="version"> The Microsoft Bing version. </param>
        /// <param name="isBaseMapLayer"> Specifies if the added layer should act as a base layer. </param>
        /// <param name="opacity"> The initial opacity of the layer. </param>
        /// <param name="icon"> The icon of the layer used within the layer gadget. </param>
        /// <param name="copyrightImagePanel"> The panel where the bing logo should be added. </param>
        public static void AddBingLayer(this WpfMap wpfMap, string name, int idx, string bingKey, BingImagerySet set, BingMapVersion version,
                                        bool isBaseMapLayer, double opacity, BitmapImage icon, Panel copyrightImagePanel)
        {
            var metaInfo = new BingMetaInfo(set, version, bingKey);

            // add a bing aerial layer
            var bingLayer = new TiledLayer(name)
            {
                TiledProvider  = new BingTiledProvider(metaInfo),
                IsBaseMapLayer = isBaseMapLayer,
                Opacity        = opacity,
                Icon           = icon
            };

            wpfMap.Layers.Insert(idx, bingLayer);

            try
            {
                var bingLogo = new Image
                {
                    Stretch             = Stretch.None,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Source = new BitmapImage(new Uri(metaInfo.LogoUri))
                };

                copyrightImagePanel.Children.Add(bingLogo);
                copyrightImagePanel.Visibility = Visibility.Visible;
            }
            catch (Exception)
            {
                //Just silently catch exceptions if the image cannot be displayed!
            }
        }