A GroupLayer based upon the Keyhole Markup Language (KML) specification that targets the Google Maps level of support.

Enhanced functionality to support more KML elements was added in the ArcGIS Silverlight/WPF/Windows Phone API's at version 2.3. This brings the KML level of functionality very close to that of the KML specification used in Google Maps.

KML is an XML tag based syntax that holds geographic information (geometric shapes, symbology, and attributes) in a file with the .kml extension. The KmlLayer also support the KMZ specification which is essentially a set of zipped KML files, folders, and other documents (e.g. images, icons, html documents, etc. ) into a single file with the .kmz extension. To view the contents of a KMZ file, rename the file with the extension .zip and use a ZIP program to explode the contents onto a hard drive location.

KmlLayer is a GroupLayer

The KmlLayer is of Type GroupLayer meaning that certain KML elements are parsed out into individual Layers in a LayerCollection. As of version 2.3 of the API's, the following KML elements are parsed into the ArcGIS Layer types of:

KML Element(s)ArcGIS Layer Type <Placemark><Point>GraphicsLayer based upon MapPoint Geometries <Placemark><LineString>GraphicsLayer based upon Polyline Geometries <Placemark><Polygon>GraphicsLayer based upon Polygon Geometries <GroundOverlay>ElementLayer

Note: The KML elements of <Folder>, <Document>, and <NetworkLink> become child KmlLayers (which can be recursive in nature depending on the KML/KMZ file) and are parsed into the ArcGIS Layer types noted in the prior table. Additionally, a KmlLayer can contain other KmlLayers (which again can be recursive).

Drilling into individual Layers and their subsequent atomic level Types of a KmlLayer GroupLayer is accomplished via the KmlLayer.ChildLayers Property. See the code example in the KmlLayer.Name Property documentation for one example of drilling into the KmlLayer GroupLayer to obtain detailed information (like: Graphic Attributes, Graphic Symbology, Graphic Geometry, ElementLayer ElementType, ElementLayer Opacity, ElementLayer Envelope, etc.) that may be useful in creating an application.

Windows Phone specific issues

The KmlLayer.MapTip Property is only works in the Silverlight and WPF API’s; it is not supported in the Windows Phone API. TIP: For Windows Phone applications, when using a Legend Control buddied with a Map Control that contains a KmlLayer, use the Legend.LayerItemsMode = "Flat" in order to see the graphical symbols in the Legend. This is not a KmlLayer specific issue, rather a function of the default Legend template not taking advantage of the TreeView Control hierarchy for GroupLayers.

WPF specific issues

There is a known issue of KmlLayer symbols briefly flickering in the upper left corner of the Windows Desktop when a WPF application starts and stops.

Accessing KML/KMZ on the local hard drive

Accessing a KmlLayer is unique in that ArcGIS Server is not required to view geographic information. Since the KmlLayer is based upon a KML or KMZ file, all that is required is a web server to host the KML/KMZ file. NOTE: ArcGIS Server has the ability to host geographic web services created in ArcMap as native KML/KMZ files.

Developers who wish to test the KmlLayer functionality using KML/KMZ files locally on their development machine have several options depending on the API platform that they are developing on.

In Silverlight:

Option #1: Developers can place the KML/KMZ file in the ClientBin directory of the test web site that is generated when creating a Silverlight application using Visual Studios built in web server (i.e. the directory that has the path: ..\[APPLICATION_NAME].Web\ClientBin). This option is the easiest method for testing KML/KMZ files when there is no web browser security issues because all of the KML/KMZ functionality is self contained. See the code example in the KmlLayer.Url Property for one common workflow example of Option #1.

NOTE: If the KML/KMZ file has hyperlinks (i.e. they begin with http://) to resources (such as other KML/KMZ files) to locations outside of your local network, IT WILL BE REQUIRED to use Option #2 for local testing of KML/KMZ files. Some common KML tags (or nested sub-tags) that can use external hyperlinks outside of your local network include the following: <href>, <Style>, <Icon>, <IconStyle>, <StyleMap>, <NetworkLink>, and <styleUrl>. Additionally, if you get a Security Exception or unhandled exception 4004 errors in Visual Studio during your Silverlight application debugging, you will most likely need to use Option #2 instead.

Option #2: If the developer has installed a web server on the same computer as Visual Studio (for example: Internet Information Server (IIS)), then they can place the KML/KMZ file in an application directory of their local web server (i.e. http://localhost). Using this option has the additional requirements of:

Setting up the correct MIME type on the web server to handle KML/KMZ files Adding a crossdomain.xml file to the root of the web server Making use of a proxy to avoid Security Exception error messages

See the code example in the KmlLayer.ProxyUrl Property for one common workflow example of Option #2.

In WPF:

Option #1: Because WPF does not have the same security restrictions as Silverlight, developers can place a KML/KMZ file anywhere on the local hard drive and provide the file path as the KmlLayer.Url (example: Url="C:\TEST_KML_FILES\Test.kml").

Option #2: If developers want to use a local web server (like IIS) to place their KML/KMZ files for testing, they are free to do so just like in Silverlight (example: Url="http://localhost/TEST_KML_FILES/Test.kml"). NOTE: WPF does not use proxies so the use of KmlLayer.ProxyUrl is not necessary (even though the local KML file may have resource links (i.e. http://) to locations outside of the local network).

In Windows Phone:

Option #1: If developers want to use a local web server (like IIS) to place their KML/KMZ files for testing, they are free to do so just like in Silverlight (example: Url="http://localhost/TEST_KML_FILES/Test.kml"). NOTE: Windows Phone does not use proxies so the use of KmlLayer.ProxyUrl is not necessary (even though the local KML file may have resource links (i.e. http://) to locations outside of the local network).

Supported KML Tags

The following table lists the KML elements supported by the KmlLayer class, and provides additional notes for elements that are conditionally supported.

Supported KML ElementSupportability Notes <altitudeMode> Only 2D supported. <atom:author> The <atom:author> 'name' attribute is stored in the ESRI.ArcGIS.Client.Graphic as an Attribute (where the key = 'name' in the key/value pairs of the IDictionary(Of String, Object)). When this value is defined on a container (<Folder> or <Document>), all <Placemark>'s in the hierarchy inherits from this value. <atom:link> The <atom:link> 'href' attribute is stored in the ESRI.ArcGIS.Client.Graphic as an Attribute (where the key = 'atomHRef' in the key/value pairs of the IDictionary(Of String, Object)). When this value is defined on a container (<Folder> or <Document>), all <Placemark>'s in the hierarchy inherits from this value. <atom:name> The <atom:name> 'href' attribute is stored in the ESRI.ArcGIS.Client.Graphic as an Attribute (where the key = 'atomHRef' in the key/value pairs of the IDictionary(Of String, Object)). When this value is defined on a container (<Folder> or <Document>), all <Placemark>'s in the hierarchy inherits from this value. <BalloonStyle> For the <BalloonStyle>, the nested <text> tag information is stored in the ESRI.ArcGIS.Client.Graphic as an Attribute (where the key = 'balloonText' in the key/value pairs of the IDictionary(Of String, Object)). NOTE: Whatever is specified as information in the <text > tag is used, there is no entity replacement. <color> Includes #AABBGGRR and #BBGGRR. <colorMode> Random mode not supported. <coordinates> <Data> Multiple <Data> tags can be nested within the <ExtendedData> tag. The <ExtendedData> tag corresponds to a System.Collections.Generic.List(Of ESRI.ArcGIS.Client.Toolkit.DataSources.Kml.KmlExtendedData). An <ExtendedData> tag is stored as a single key/value pair in the IDictionary(Of String, Object)) of the Graphic.Attributes Property (where the key = 'extendedData' in the key/value pairs of the IDictionary(Of String, Object)). Each <Data> tag holds three attributes: 'name', 'displayname', and 'value' and is stored as a KmlExtendedData object of the System.Collections.Generic.List(Of ESRI.ArcGIS.Client.Toolkit.DataSources.Kml.KmlExtendedData). Thus, the <Data> 'name' attribute maps to a KmlExtendedData.Name Property; the <Data> 'displayname' attribute maps to the KmlExtendedData.DisplayName Property; and the <Data> 'value' attribute maps to the KmlExtendedData.Value Property. <description> For the <description> tag the information is stored in the ESRI.ArcGIS.Client.Graphic as an Attribute (where the key = 'description' in the key/value pairs of the IDictionary(Of String, Object)). NOTE: Whatever is specified as information in the <description> tag is used, there is no entity replacement. The HTML content is allowed but is sanitized to protect from cross-browser attacks; entity replacements of the form $[dataName] are unsupported. <Document> From v2.3, the <Document> tag becomes ESRI.ArcGIS.Client.GroupLayers. <east> Part of <LatLonBox>. <ExtendedData> Multiple <Data> tags can be nested within the <ExtendedData> tag. The <ExtendedData> tag corresponds to a System.Collections.Generic.List(Of ESRI.ArcGIS.Client.Toolkit.DataSources.Kml.KmlExtendedData). An <ExtendedData> tag is stored as a single key/value pair in the IDictionary(Of String, Object)) of the Graphic.Attributes Property (where the key = 'extendedData' in the key/value pairs of the IDictionary(Of String, Object)). Each <Data> tag holds three attributes: 'name', 'displayname', and 'value' and is stored as a KmlExtendedData object of the System.Collections.Generic.List(Of ESRI.ArcGIS.Client.Toolkit.DataSources.Kml.KmlExtendedData). Thus, the <Data> 'name' attribute maps to a KmlExtendedData.Name Property; the <Data> 'displayname' attribute maps to the KmlExtendedData.DisplayName Property; and the <Data> 'value' attribute maps to the KmlExtendedData.Value Property. No support for SchemaData. <fill> <Folder> From v2.3, the <Folder> tag becomes ESRI.ArcGIS.Client.GroupLayers. <GroundOverlay> From v2.3, an ESRI.ArcGIS.Client.ElementLayer is created by <Folder> and <Document> tags to contain all the <GroundOverlay> tags of the container. Nested tags of <LatLongBox>, <rotation>, <color>, and <icon> are used. <heading> Supported when part of an <IconStyle> element for proper rotation of a point's image. <hotSpot> Supported for Symbol creation. <href> <Icon> Only the 'href' element of this complex element is supported. Rotation and scaling are supported. <IconStyle> <innerBoundaryIs> Only single interior ring supported. <kml> It's the root element of any KML document. <LatLonBox> Support for <Placemark> tags. Supported from v2.3 for <GroundOverlay> tags. <LinearRing> Supported, but only makes use of the <coordinates> sub element. <LineString> Supported, but only makes use of the <coordinates> sub element. <LineStyle> <Link> Supported, but only makes use of the <href> sub element. <MultiGeometry> Rendered but displayed as separate features in left side panel. <name> For the <name> tag the information is stored in the ESRI.ArcGIS.Client.Graphic as an Attribute (where the key = 'name' in the key/value pairs of the IDictionary(Of String, Object)). NOTE: Whatever is specified as information in the <description> tag is used, there is no entity replacement. <NetworkLink> From v2.3 support for <refreshInterval> tag and 'OnInterval' RefreshMode. Becomes a sub-layer in the ESRI.ArcGIS.Client.GroupLayer. <NetworkLinkControl> 'MinRefreshPeriod' supported from v2.3. <north> Supported as part of <LatLonBox>. <outerBoundaryIs> Implicitly from <LinearRing> order. <outline> <Placemark> Becomes an ESRI.ArcGIS.Client.Graphic in an ESRI.ArcGIS.Client.GraphicsLayer. <Point> Supported, but only makes use of the <coordinates> sub element. <Polygon> Supported, but only makes use of the <OuterBoundaryIs> and <InnerBoundaryIs> sub elements. <PolyStyle> Makes use of the tags <color>, <fill>, and <outline>. <refreshInterval> Supported from v2.3. <refreshMode> 'OnInterval' mode supported from v2.3. <south> Supported as part of <LatLonBox>. <Style> Supported, but only <IconStyle>, <LineStyle>, and <PolyStyle> sub-elements are supported. <StyleMap> Only 'Normal' style supported. 'highlight' style not supported. <text> <value> Replacement of $[geDirections] is not supported. <visibility> Visibility of containers (<Folder>/<Document>/<NetworkLink>) supported from v2.3. Visibility of features not supported. <west> Supported as part of <LatLonBox>. <width>
상속: GroupLayer
 public static void SetVisibleLayerIDs(KmlLayer layer, string value)
 {
     layer.SetValue(VisibleLayerIDsProperty, value);
     if (!string.IsNullOrEmpty(value))
     {
         layer.SetVisibilityByIDs(value.Split(',').Select(p => Convert.ToInt32(p)));
     }
 }
예제 #2
0
파일: KmlContent.cs 프로젝트: TNOCS/csTouch
 public void Add()
 {
     IsRunning = true;
     kml = new KmlLayer { ID = Name, Url = Location };
     gl = AppState.ViewDef.FindOrCreateGroupLayer(Folder);
     if (gl != null) gl.ChildLayers.Add(kml);
     kml.Initialize();
 }
예제 #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="KmlLayer"/> class which will be a child of another <see cref="KmlLayer"/>.
 /// </summary>
 /// <param name="parentLayer">The parent layer.</param>
 internal KmlLayer(KmlLayer parentLayer)
     : this()
 {
     _parentLayer = parentLayer;
     ProjectionService = parentLayer.ProjectionService;
     ProxyUrl = parentLayer.ProxyUrl;
     VisibleLayers = parentLayer.VisibleLayers;
     InitializationFailed += KmlLayer_InitializationFailed; // To avoid crash and report error to parent
     #if !WINDOWS_PHONE
     MapTip = parentLayer.MapTip;
     #endif
     #if !SILVERLIGHT || WINDOWS_PHONE
     Credentials = parentLayer.Credentials;
     #endif
     #if !SILVERLIGHT
     ClientCertificate = parentLayer.ClientCertificate;
     #endif
 }
예제 #4
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;
        }
예제 #5
0
        private static IEnumerable<int> InternalGenerateVisibilityIDs(KmlLayer layer)
        {
            // For NetworkLinks (i.e. _isRoot), don't go through the hierarchy and return an empty enumeration (Network links visibility is not managed by arcgis.com)
            if (layer._isRoot)
                return Enumerable.Empty<int>();

            // Create an enumeration either empty (if the layer is not visible) or containing the current ID (if the layer is visible)
            IEnumerable<int> ownIDs = layer.Visible ? new[] { layer._folderId } : Enumerable.Empty<int>();

            // Go recursively through the sublayers and  concat with  the visible IDs of the sublayers
            return ownIDs.Concat(layer.ChildLayers.OfType<KmlLayer>().SelectMany(InternalGenerateVisibilityIDs));
        }
예제 #6
0
 private static IEnumerable<KmlLayer> GetParentsAndSelf(KmlLayer kmlLayer)
 {
     while (kmlLayer != null)
     {
         yield return kmlLayer;
         kmlLayer = kmlLayer._parentLayer;
     }
 }
 public static string GetVisibleLayerIDs(KmlLayer layer)
 {
     return (string) layer.GetValue(VisibleLayerIDsProperty);
 }
예제 #8
0
 private void FindGraphicsLayers(KmlLayer kmlLayer)
 {
     foreach (Layer layer in kmlLayer.ChildLayers)
     {
         if (layer is GraphicsLayer)
         {
             graphicsLayers.Add((GraphicsLayer)layer);
         }
         else if (layer is KmlLayer)
         {
             FindGraphicsLayers((KmlLayer)layer);
         }
     }
 }
예제 #9
0
        public void RenderServerImage(string url, int[] visibleLayers)
        {
            this.url = url;

            KmlLayer shapeLayer = myMap.Layers[layerId.ToString()] as KmlLayer;
            if (shapeLayer != null)
            {
                myMap.Layers.Remove(shapeLayer);
            }

            shapeLayer = new KmlLayer();
            shapeLayer.ID = layerId.ToString();
            shapeLayer.Url = new Uri(url);
            shapeLayer.Initialized += new EventHandler<EventArgs>(shapeLayer_Initialized);
            if (visibleLayers != null)
            {
                //shapeLayer.VisibleLayers = visibleLayers;
            }
            myMap.Layers.Add(shapeLayer);

            myMap.Extent = shapeLayer.FullExtent;
        }
예제 #10
0
파일: ShapeLayer.cs 프로젝트: TNOCS/csTouch
 public static void AddKmlFile(string filePath, GroupLayer curGrLayer)
 {
     var fi = new FileInfo(filePath);
     var kmlLayer = new KmlLayer { Url = new Uri(fi.FullName), ID = fi.Name} ;
     kmlLayer.Initialize();
     kmlLayer.Visible = false;
     curGrLayer.ChildLayers.Add(kmlLayer);
 }
        public void LoadKml(string url)
        {
            if (!string.IsNullOrEmpty(url))
            {
                this.url = url;
                KmlLayer shapeLayer = myMap.Layers[layerId.ToString()] as KmlLayer;
                if (shapeLayer != null)
                {
                    myMap.Layers.Remove(shapeLayer);
                }

                shapeLayer = new KmlLayer();
                shapeLayer.ID = layerId.ToString();
                shapeLayer.Url = new Uri(url);
                shapeLayer.Initialized += new EventHandler<EventArgs>(shapeLayer_Initialized);
                myMap.Layers.Add(shapeLayer);

                myMap.Extent = shapeLayer.FullExtent;
            }
        }
		private static IEnumerable<KmlLayer> GetParents(KmlLayer kmlLayer)
		{
			if (kmlLayer._parentLayer == null)
				return Enumerable.Empty<KmlLayer>();

			return (new List<KmlLayer>() { kmlLayer._parentLayer }).Concat(GetParents(kmlLayer._parentLayer));
		}