Common_CustomDataSource_CSharp\REXMLDataSource_CSharp\MapFunctionality.cs
// Copyright 2011 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the use restrictions. // namespace REXMLDataSource_CSharp { // Along with IGISDataSource and IGISResource, IGISFunctionality is one of the three required // interfaces for any Web ADF Data Source implementation. This interface is responsible for // providing members to functionally interact with the underlying data. Essentially, an // IGISFunctionality implementation can be thought of as describing what can be done with the // data. // // This particular implementation inherits from IMapFunctionality, which implements // IGISFunctionality. IMapFunctionality provides methods and properties that are the foundation // of map operations like zoom and pan. public class MapFunctionality : ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality { #region Instance Variables private ESRI.ArcGIS.ADF.Web.DisplaySettings m_displaySettings = null; private System.Web.UI.WebControls.WebControl m_webControl = null; private bool m_maintainsState = false; private ESRI.ArcGIS.ADF.Web.SpatialReference.SpatialReference m_spatialReference = null; private string m_name = string.Empty; private ESRI.ArcGIS.ADF.Web.DataSources.IGISResource m_gisResource = null; bool m_initialized = false; private ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsDataSet m_graphicsDataSet = null; #endregion #region Constructor // Constructor that initializes functionality name and the resource with which the // functionality is associated public MapFunctionality(string name, REXMLDataSource_CSharp.MapResource resource) { m_name = name; m_gisResource = resource; } #endregion #region REXML MapFunctionality Members // Allows access to the MapResource object associated with the functionality public REXMLDataSource_CSharp.MapResource MapResource { get { return m_gisResource as REXMLDataSource_CSharp.MapResource; } } // Key for storing and retrieving object state to and from the underlying data source's state table private string FunctionalityStateKey { get { string szResource = m_gisResource.GetType().ToString() + ":" + m_gisResource.Name; string szThis = this.GetType().ToString() + ":" + m_name; return (szResource + "," + szThis); } } // Allows read access to the GraphicsDataSet containing the REXML data public ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsDataSet GraphicsDataSet { get { // Check whether the functionality maintains state if (!m_maintainsState) { // Get a reference to the MapResource associated with the functionality REXMLDataSource_CSharp.MapResource mapResource = m_gisResource as REXMLDataSource_CSharp.MapResource; // If the MapResource's GraphicsDataSet is null, return null. Otherwise, // return the dataset. return mapResource == null ? null : mapResource.Graphics; } else { // check whether the functionality instance's graphics dataset is null if (m_graphicsDataSet != null) { // return the instance graphics dataset return m_graphicsDataSet; } else { // Get a reference to the MapResource associated with the functionality REXMLDataSource_CSharp.MapResource mapResource = m_gisResource as REXMLDataSource_CSharp.MapResource; // Make sure neither the MapResource nor the MapResource's graphics dataset // are null if (mapResource != null && mapResource.Graphics != null) { // Initialize the instance's graphics dataset as a clone of the associated // MapResource's m_graphicsDataSet = mapResource.Graphics.Clone(); } // return the functionality instance's graphics dataset return m_graphicsDataSet; } } } } // Returns the extent of the Web ADF Map Control associated with the functionality public ESRI.ArcGIS.ADF.Web.Geometry.Envelope GetMapExtent() { // Attempt to get a reference to the Map Control associated with the instance by casting // the instance's WebControl member ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = m_webControl as ESRI.ArcGIS.ADF.Web.UI.WebControls.Map; // If a reference was successfully established, return the contents of the control's Extent // property. Otherwise, return null. if (adfMap == null) return null; else return adfMap.Extent; } // Returns the screen width and height in pixels of the Web ADF Map Control associated // with the functionality public void GetMapDimensions(out int width, out int height) { width = -1; height = -1; // Attempt to get a reference to the Map Control associated with the instance by casting // the instance's WebControl member ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = m_webControl as ESRI.ArcGIS.ADF.Web.UI.WebControls.Map; // Make sure a reference to the Map Control was successfully established if (adfMap == null) return; // Make sure the Map Control has a valid TilingScheme for the REXML resource if (adfMap.GetTilingScheme(m_gisResource.Name) == null) return; // Set the width and height output parameters width = adfMap.GetTilingScheme(m_gisResource.Name).ViewWidth; height = adfMap.GetTilingScheme(m_gisResource.Name).ViewHeight; } // Allows internal retrieval by layer ID of a layer referenced by the functionality private ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer getLayer(string layerID) { // Cast the table in the functionality's graphics dataset at the passed-in layer ID // to a Web ADF GraphicsLayer and return ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer adfGraphicsLayer = (ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer)m_graphicsDataSet.Tables[layerID]; return adfGraphicsLayer; } #endregion #region IMapFunctionality Members #region IMapFunctionality Properties // Allows read/write access to the flag indicating whether the functionality maintains state public bool MaintainsState { get { return m_maintainsState; } set { m_maintainsState = value; } } // Allows read/write access to the DisplaySettings of the MapResource instance associated with // the functionality public ESRI.ArcGIS.ADF.Web.DisplaySettings DisplaySettings { get { // Get a reference to the functionality's associated MapResource REXMLDataSource_CSharp.MapResource rexmlMapResource = m_gisResource as REXMLDataSource_CSharp.MapResource; // Check the flag indicating whether the functionality maintains state. If not, return // the associated MapResource's DisplaySettings if (m_maintainsState) { // Check whether the functionality instance's DisplaySettings object has been initialized if (m_displaySettings == null) { // Set the instance's DisplaySettings object to a clone of the associated // MapResource's DisplaySettings m_displaySettings = (ESRI.ArcGIS.ADF.Web.DisplaySettings)rexmlMapResource.DisplaySettings.Clone(); } // Return the functionality instance's DisplaySettings return m_displaySettings; } else return rexmlMapResource.DisplaySettings; } set { // Get a reference to the functionality's associated MapResource REXMLDataSource_CSharp.MapResource rexmlMapResource = m_gisResource as REXMLDataSource_CSharp.MapResource; // Check whether the functionality maintains state. If so, set the functionality's // DisplaySettings object to the passed-in value. If not, set the associated MapResource's // DisplaySettings object to the passed-in value. if (m_maintainsState) m_displaySettings = value; else rexmlMapResource.DisplaySettings = value; } } // Not implemented here, but required to be stubbed out for implementations of IMapFunctionality. public ESRI.ArcGIS.ADF.Web.DataSources.Units Units { get { throw new System.NotImplementedException(); } } // Allows read access to the IDs of the layers referenced by the functionality's graphics dataset public object[] LayerIDs { get { // Make sure neither the functionality's graphics dataset nor the graphics dataset's // tables collection are null if (m_graphicsDataSet == null || m_graphicsDataSet.Tables == null) return null; // Dimension the layer ID array with the number of tables in the functionality's // graphics dataset object[] layerIDs = new object[m_graphicsDataSet.Tables.Count]; // Iterate through the tables in the functionality's graphics dataset, adding the // name of each to the layer ID array for (int i = 0; i < m_graphicsDataSet.Tables.Count; i++) { layerIDs[i] = m_graphicsDataSet.Tables[i].TableName; } return layerIDs; } } // Allows read/write access to the functionality's spatial reference public ESRI.ArcGIS.ADF.Web.SpatialReference.SpatialReference SpatialReference { get { return m_spatialReference; } set { m_spatialReference = value; } } // This implementation does not support rotation, but the property must be stubbed out // in order to implement IMapFunctionality public double Rotation { get { return double.NaN; } } #endregion #region IMapFunctionality Methods // Applies the ImageDescriptor of the functionality's display settings to its graphics dataset public void ApplyStateToDataSourceObjects() { // Make sure the functionality's graphics dataset is not null if (m_graphicsDataSet != null) { // If the functionality's display settings object is not null, apply its ImageDescriptor // to the graphics dataset. This is actually applying the ImageDescriptor to the // underlying data source, since the graphics dataset references that of the data source. if (m_displaySettings != null) m_graphicsDataSet.ImageDescriptor = m_displaySettings.ImageDescriptor; } } // Retrieves the ImageDescriptor of the functionality's graphic dataset and applies it to the // functionality's display settings public void GetStateFromDataSourceObjects() { // Make sure the instance's graphics dataset is not null if (m_graphicsDataSet != null) { // If the instance's display settings object is not null, set its ImageDescriptor to // that of the instance's graphics dataset. This is actually retrieiving the // ImageDescriptor from the underlying data source, since the graphics dataset references // that of the data source. if (m_displaySettings != null) m_displaySettings.ImageDescriptor = m_graphicsDataSet.ImageDescriptor; } } // Retrieves the names and IDs of the layers referenced by the functionality instance public void GetLayers(out string[] layerIDs, out string[] layerNames) { layerIDs = layerNames = null; // Make sure neither the instance's graphics dataset nor the graphics dataset's tables // collection are null if (m_graphicsDataSet == null || m_graphicsDataSet.Tables == null) return; // Dimension the layer ID and names arrays with the number of tables in the graphics // dataset's tables collection layerIDs = new string[m_graphicsDataSet.Tables.Count]; layerNames = new string[m_graphicsDataSet.Tables.Count]; // Iterate through the graphics dataset's tables collection, storing the name of each // in both the layer ID and names arrays. Note that for graphics layers, the layer ID // is the same as the layer name. for (int i = 0; i < m_graphicsDataSet.Tables.Count; i++) { layerIDs[i] = m_graphicsDataSet.Tables[i].TableName; layerNames[i] = m_graphicsDataSet.Tables[i].TableName; } return; } // Not meaningfully implemented here, but stubbed out in order to implement IMapFunctionality public void GetVisibleScale(string layerid, out double minscale, out double maxscale) { // At a minimum, required for MapTips minscale = double.NaN; maxscale = double.NaN; } // Not implemented public double GetScale(ESRI.ArcGIS.ADF.Web.Geometry.Envelope extent, int mapWidth, int mapHeight) { throw new System.NotImplementedException(); } // Not meaningfully implemented public System.Collections.Generic.Dictionary<string, string> GetCopyrightText() { return new System.Collections.Generic.Dictionary<string, string>(); } // Returns a MapImage containing a map of the layers referenced by the functionality (in MIME // data or as a url) at the passed-in extent public ESRI.ArcGIS.ADF.Web.MapImage DrawExtent (ESRI.ArcGIS.ADF.Web.Geometry.Envelope extentToDraw) { // Make sure the functionality instance's graphics dataset is not null if (m_graphicsDataSet != null) { // Update the state of the underlying data source ApplyStateToDataSourceObjects(); // Return the MapImage generated by the graphics dataset's DrawExtent method return m_graphicsDataSet.DrawExtent(extentToDraw); } else return null; } // Returns the visibility of the layer with the passed-in ID public bool GetLayerVisibility(string layerID) { return getLayer(layerID).Visible; } // Sets the visibility of the layer with the passed-in ID to the passed-in boolean public void SetLayerVisibility(string layerID, bool visible) { getLayer(layerID).Visible = visible; } #endregion #endregion #region IGISFunctionality Members #region IGISFunctionality Properties // Allows read/write access to the functionality instance's name public string Name { get { return m_name; } set { m_name = value; } } // Allows read/write access to the GISResource associated with the functionality instance public ESRI.ArcGIS.ADF.Web.DataSources.IGISResource Resource { get { return m_gisResource; } set { m_gisResource = value; } } // Allows read access to the instance member indicating whether the functionality has been initialized public bool Initialized { get { return m_initialized; } } // Allows retrieving or setting the WebControl associated with the functionality instance public System.Web.UI.WebControls.WebControl WebControl { get { return m_webControl; } set { m_webControl = value; } } #endregion #region IGISFunctionality Methods // Loads the state of the functionality object from the data source's state table public void LoadState() { // make sure references to the functionality's associated GISResource, the GISResource's // underlying GISDataSource, and the GISDataSource's state table are all valid if (m_gisResource == null || m_gisResource.DataSource == null || m_gisResource.DataSource.State == null) { throw new System.Exception("The Resource associated with this functionality is not valid."); } // Some of the functionality instance's properties need to be explicitly stored in the state // table, while others do not. An overview of these properties and the reasons for storing or // not storing them is as follows: // These properties are shared with and managed by the associated MapResource: // - Display Settings // - DataSource objects: GraphicsDataSet // These properties are shared with and managed by the associated DataSource objects: // - DisplaySettings.ImageDescriptor // These properties are dynamic and therefore do not need to be stored in state: // - LayerIDs // - Scale // - Rotation // - Extent // These properties are non-dynamic and exclusive to this instance, so they need to be // stored in state: // - WebControl // - MaintainsState // - SpatialReference // Retrieve the functionality's state from the underlying data source's state table. The // object state will be stored in the table at the index indicated by the private property // FunctionalityStateKey object functionalityState = m_gisResource.DataSource.State[FunctionalityStateKey]; // Check whether the state was found if (functionalityState != null) { // Cast the state object to a REXML MapFunctionality REXMLDataSource_CSharp.MapFunctionality rexmlMapFunctionality = functionalityState as REXMLDataSource_CSharp.MapFunctionality; // Get the properties stored in functionality state (as noted above) from stored state and // assign them to the appropriate instance variables m_maintainsState = rexmlMapFunctionality.MaintainsState; m_webControl = rexmlMapFunctionality.WebControl; m_spatialReference = rexmlMapFunctionality.SpatialReference; // If maintainsState, retrieve this functionality's own copies of the properties that are // shared with the associated MapResource instance and assign them to the appropriate // instance variables if (m_maintainsState) { m_displaySettings = rexmlMapFunctionality.DisplaySettings; m_graphicsDataSet = rexmlMapFunctionality.GraphicsDataSet; } } // Load the properties that are shared with the instance's associated DataSource objects. // This will initialize the relevant instance variables with values from those objects. GetStateFromDataSourceObjects(); // Any necessary logic for handling dynamic properties (listed above) would go here. } // Stores the functionality's state in the underlying data source's state table. public void SaveState() { // make sure references to the functionality's associated GISResource, the GISResource's // underlying GISDataSource, and the GISDataSource's state table are all valid if (m_gisResource == null) return; if (m_gisResource.DataSource == null) return; if (m_gisResource.DataSource.State == null) return; // Update the state of the underlying data source objects with relevant properties of the // functionality instance ApplyStateToDataSourceObjects(); // Store the functionality instance in the data source's state table m_gisResource.DataSource.State[FunctionalityStateKey] = this; } // Set the flag indicating whether the functionality is intitialized to true. Any necessary // start-up logic (i.e. instance variable initialization) should go here. public void Initialize() { m_graphicsDataSet = this.GraphicsDataSet; m_initialized = true; } // Set the flag indicating whether the functionality is intitialized to false. Any necessary // disposal logic (e.g. releasing object references) should go here. Note that, if there is // additional logic here, users of this class will have to EXPLCITLY call dispose. It is not // invoked by other Web ADF components or the Page life-cycle. public void Dispose() { m_initialized = false; } // Retrieves boolean indicating whether the operation defined by the passed-in string is // supported by this implementation. Here, only GetScale is explicitly not implemented. public bool Supports(string operation) { if (operation == "GetScale") return false; return true; } #endregion #endregion } }