/// <summary> /// Initializes a <see cref="Map"/> object based on a web map /// </summary> /// <param name="map">The map to initialize</param> /// <param name="e">The <see cref="GetMapCompletedEventArgs"/> object containing the web map's information. /// This is the event args type returned to the <see cref="Document.GetMapCompleted"/> event.</param> public static void InitializeFromWebMap(this Map map, GetMapCompletedEventArgs e, EventHandler <EventArgs> onLayerInitFailed = null) { map.Layers.Clear(); if (e.Map.Extent != null && e.Map.Extent.SpatialReference != null && e.Map.Extent.SpatialReference.IsWebMercator() && double.IsNegativeInfinity(e.Map.Extent.YMin) && double.IsPositiveInfinity(e.Map.Extent.YMax)) { e.Map.Extent.YMin = double.NaN; e.Map.Extent.YMax = double.NaN; } map.Extent = e.Map.Extent; List <Layer> layers = new List <Layer>(); List <Layer> basemapLayers = new List <Layer>(); IEnumerable <Layer> allLayers = e.Map.Layers.FlattenLayers(); List <string> featureCollectionLayerNames = new List <string>(); // Create collection of layers to add to the map based on the layers in the web map foreach (Layer layer in allLayers) { // Set ShowLegend to true for each layer. The framework handles layer visibility // in MapContents otherwise. layer.ShowLegend = true; if (layer is ESRI.ArcGIS.Client.Bing.TileLayer) { ESRI.ArcGIS.Mapping.Core.LayerExtensions.SetUsesBingAppID((ESRI.ArcGIS.Client.Bing.TileLayer)layer, true); } layer.ProcessWebMapProperties(e.DocumentValues); // Check whether any layers flagged for adding to the map have the same ID as the current one. Layers // with the same ID represent feature collections that show up as part of the same layer in the online // viewers, but are actually serialized as separate layers. if (!(layer is GraphicsLayer) || !layers.Any(l => l.ID == layer.ID || l.DisplayName == layer.DisplayName || featureCollectionLayerNames.Contains(layer.DisplayName))) { if ((bool)(layer.GetValue(ESRI.ArcGIS.Client.WebMap.Document.IsBaseMapProperty))) { basemapLayers.Add(layer); } layers.Add(layer); } else // Layer belongs to a multi-layer feature collection. Combine with layer already included in the list. { GraphicsLayer currentLayer = layers.First(l => l.ID == layer.ID || l.DisplayName == layer.DisplayName || featureCollectionLayerNames.Contains(layer.DisplayName)) as GraphicsLayer; GraphicsLayer newLayer = layer as GraphicsLayer; if (newLayer != null && newLayer.Graphics.Count > 0) { if (currentLayer != null && LayerExtensions.GetGeometryType(currentLayer) == LayerExtensions.GetGeometryType(newLayer)) { // Layers have the same geometry type - just copy the features from one to the other newLayer.Graphics.MoveTo(currentLayer.Graphics); } else if (currentLayer != null && currentLayer.Graphics.Count == 0) { // Geometry types don't match, but the layer already added to the list doesn't have any // features graphics. Override the renderer from the added layer with that from the current // one and copy over the features in the currently layer. currentLayer.Renderer = newLayer.Renderer; newLayer.Graphics.MoveTo(currentLayer.Graphics); } else { // Geometry types don't match, but both layers have features. We don't want to put the // features in the same layer because that eliminates the ability to configure the layer's // renderer. So create separate layers. // The layers will have the same name by default. To avoid having multiple layers with the // same name, append a suffix that indicates the geometry type, i.e. points, lines, or areas. if (currentLayer != null) { currentLayer.AppendGeometryToLayerName(); featureCollectionLayerNames.Add(layer.DisplayName); } newLayer.AppendGeometryToLayerName(); // The layers will have the same ID by default, which can cause unexpected behavior. // So give one of them a new ID. newLayer.ID = Guid.NewGuid().ToString("N"); layers.Add(newLayer); // Look in the web map's layers for other layers that have the same geometry type as the new // layer. Since the new layer has a new ID, and the logic here relies on ID to determine // whether to merge with another layer, we need to update the IDs of the layers yet to be // processed to match the new ID. IEnumerable <Layer> others = allLayers.Where( l => (l.ID == layer.ID) && LayerExtensions.GetGeometryType((GraphicsLayer)l) == LayerExtensions.GetGeometryType((GraphicsLayer)layer)); foreach (GraphicsLayer gLayer in others) { gLayer.ID = newLayer.ID; } } } } } #region Get Basemap Title if (basemapLayers.Count > 0 && e.DocumentValues.ContainsKey("baseMap")) { IDictionary <string, object> dict = e.DocumentValues["baseMap"] as IDictionary <string, object>; if (dict != null) { string baseMapTitle = "Basemap"; if (dict.ContainsKey("title")) { baseMapTitle = dict["title"] as string; if (!string.IsNullOrWhiteSpace(baseMapTitle)) { LayerExtensions.SetLayerName(basemapLayers[0], baseMapTitle); } } //Mark reference layers if (basemapLayers.Count > 1) { for (int i = 1; i < basemapLayers.Count; i++) { LayerExtensions.SetIsReferenceLayer(basemapLayers[i], true); //Do not show in map contents ESRI.ArcGIS.Client.Extensibility.LayerProperties.SetIsVisibleInMapContents(basemapLayers[i], false); } } } } #endregion e.Map.Layers.Clear(); foreach (Layer layer in layers) { if (onLayerInitFailed != null) { layer.InitializationFailed += onLayerInitFailed; } map.Layers.Add(layer); } #region Get map items and add any notes if (e.DocumentValues != null) { foreach (KeyValuePair <string, object> pair in e.DocumentValues) { if (pair.Key == "MapItems") { List <GraphicsLayer> noteLayers = new List <GraphicsLayer>(); #region Get note layers List <object> items = pair.Value as List <object>; if (items == null) { continue; } foreach (var item in items) { IDictionary <string, object> dict = item as IDictionary <string, object>; if (dict != null) { #region If note, add to notelayers if (dict.ContainsKey("__type") && dict["__type"].ToString() == "Note:#ESRI.ArcGIS.Mapping.Controls.ArcGISOnline") { if (dict.ContainsKey("Geometry") && dict.ContainsKey("Name")) { string name = dict["Name"] as string; IDictionary <string, object> gDict = dict["Geometry"] as IDictionary <string, object>; if (gDict == null) { continue; } ESRI.ArcGIS.Client.Geometry.Geometry geometry = null; if (gDict.ContainsKey("__type") && gDict["__type"] is string) { if (gDict["__type"].ToString() == "point:#ESRI.ArcGIS.Client.Geometry") { geometry = CreatePoint(gDict); } else if (gDict["__type"].ToString() == "Polyline:#ESRI.ArcGIS.Client.Geometry") { if (gDict.ContainsKey("paths") && gDict["paths"] is List <object> ) { List <object> paths = gDict["paths"] as List <object>; Polyline line = new Polyline(); if (paths != null) { foreach (object path in paths) { List <object> points = path as List <object>; ESRI.ArcGIS.Client.Geometry.PointCollection pts = new ESRI.ArcGIS.Client.Geometry.PointCollection(); foreach (object point in points) { if (point is IDictionary <string, object> ) { pts.Add(CreatePoint(point as IDictionary <string, object>)); } } line.Paths.Add(pts); } geometry = line; } } } else if (gDict["__type"].ToString() == "Polygon:#ESRI.ArcGIS.Client.Geometry") { if (gDict.ContainsKey("rings") && gDict["rings"] is List <object> ) { List <object> rings = gDict["rings"] as List <object>; Polygon gon = new Polygon(); if (rings != null) { foreach (object ring in rings) { List <object> points = ring as List <object>; ESRI.ArcGIS.Client.Geometry.PointCollection pts = new ESRI.ArcGIS.Client.Geometry.PointCollection(); foreach (object point in points) { if (point is IDictionary <string, object> ) { pts.Add(CreatePoint(point as IDictionary <string, object>)); } } gon.Rings.Add(pts); } geometry = gon; } } } } if (geometry != null && gDict.ContainsKey("spatialReference")) { IDictionary <string, object> srDict = gDict["spatialReference"] as IDictionary <string, object>; if (srDict != null) { if (srDict.ContainsKey("wkid")) { geometry.SpatialReference = new SpatialReference() { WKID = Int32.Parse(srDict["wkid"].ToString()) } } ; else if (srDict.ContainsKey("wkt")) { geometry.SpatialReference = new SpatialReference() { WKT = srDict["wkt"].ToString() } } ; } } if (geometry != null) { GraphicsLayer glayer = ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Note.CreateGraphicsLayer(name, new Graphic() { Geometry = geometry }, map); if (dict.ContainsKey("Visible")) { bool visible = true; try { visible = (bool)(dict["Visible"]); } catch { } glayer.Visible = visible; } noteLayers.Add(glayer); } } } #endregion } } if (noteLayers.Count > 0) { for (int i = noteLayers.Count - 1; i >= 0; i--) { if (noteLayers[i] != null) { map.Layers.Add(noteLayers[i]); } } } #endregion } } } #endregion }