Dynamic Display layer sample
CustomLayerBase.vb
' Copyright 2006 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.
'
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections
Imports System.Data
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.Display
''' <summary>
''' Summary description for clsCustomLayer.
''' </summary>
Public MustInherit Class DynamicLayerBase : Inherits Control : Implements ILayer, IDynamicLayer, ILayerExtensions, IGeoDataset, IPersistVariant, ILayerGeneralProperties, IEnumerable, IDisposable
#Region "Class members"
''' <summary>
''' Keep the layer's extent. Returned by the ILayer::Extent property
''' </summary>
''' <remarks>The extent should be spatial-referenced to the DateFrame's spatial reference.
''' </remarks>
Protected m_extent As IEnvelope = Nothing
''' <summary>
''' Store the layer's underlying data spatial reference. Returned by IGeoDataset::SpatialReference.
''' </summary>
''' <remarks>This spatial reference should not be reprojected. In your inheriting
''' class you will need to have another parameter that will keep the DataFrame's spatial reference
''' that would use to reproject the geometries and the extent of the layer.</remarks>
Protected m_spatialRef As ISpatialReference = Nothing
''' <summary>
''' Layer's name. Returned by ILayer::Name property
''' </summary>
Protected m_sName As String
''' <summary>
''' Flag which determines whether the layers is visible. Returned by ILayer::Visible
''' </summary>
''' <remarks>You should use this member in your inherited class in the Draw method.</remarks>
Protected m_visible As Boolean
''' <summary>
''' determines whether the layers is cached
''' </summary>
Protected m_IsCached As Boolean
''' <summary>
''' Flag thich determine whether the layer is valid (connected to its data source, has valid information etc.).
''' Returned by ILAyer::Valid.
''' </summary>
''' <remarks>You can use this flag to determine for example whether the layer can be available or not.</remarks>
Protected m_bValid As Boolean = True
''' <summary>
''' Keep the maximum scale value at which the layer will display
''' </summary>
Protected m_MaximumScale As Double
''' <summary>
''' Keep the minimum scale value at which the layer will display
''' </summary>
Protected m_MinimumScale As Double
''' <summary>
''' determines whether the layers is supposed to show its MapTips
''' </summary>
Protected m_ShowTips As Boolean
''' <summary>
''' the layer dirty flag which determine whether its display list need to be recreate
''' </summary>
Protected m_bIsImmediateDirty As Boolean = False
''' <summary>
''' the layer dirty flag which determine whether its display list need to be recreate
''' </summary>
Protected m_bIsCompiledDirty As Boolean = False
''' <summary>
''' The rate in which the DynamicDisplay recompile its display lists
''' </summary>
Protected m_nDynamicRecompileRate As Integer = -1
''' <summary>
''' The layer's UID
''' </summary>
Protected m_uid As UID
' <summary>
' An arraylist to store the layer's extensions.
' </summary>
Protected m_extensions As ArrayList = Nothing
''' <summary>
''' The data structure for the custom layer
''' </summary>
''' <remarks>By default, the DataTable gets initialized in the BaseClass Ctor with an ID column
''' which is AutoIncremented. The BaseClass also support enumerator which is actually en enumerator of
''' the table as well as a direct indexer.</remarks>
Protected m_table As DataTable
#End Region
#Region "class constructor"
''' <summary>
''' Default constructor
''' </summary>
Public Sub New()
m_sName = String.Empty
m_visible = True
m_IsCached = False
m_MaximumScale = 0
m_MinimumScale = 0
m_table = New DataTable("RECORDS")
m_table.Columns.Add("ID", GetType(Long))
m_extent = New EnvelopeClass()
m_extent.SetEmpty()
m_uid = New UID()
m_extensions = New ArrayList()
'make sure tha the control got created and that it has a valid handle
Me.CreateHandle()
Me.CreateControl()
End Sub
#End Region
#Region "IGeoDataset Members"
''' <summary>
'''The layers geodataset extent which is a union of the extents of all
''' the items of the layer
''' </summary>
''' <remarks>In your inheriting class, consider the following code to calculate the layer's extent:
''' <code>
''' public override IEnvelope Extent
'''{
''' get
''' {
''' m_extent = GetLayerExtent();
''' if (null == m_extent )
''' return null;
'''
''' IEnvelope env = ((IClone)m_extent ).Clone() as IEnvelope;
''' if(null != m_layerSpatialRef)
''' env.Project(m_layerSpatialRef);
'''
''' return env;
''' }
'''}
''' private IEnvelope GetLayerExtent()
'''{
''' if (null == base.m_spRef)
''' {
''' base.m_spRef = CreateGeographicSpatialReference();
''' }
'''
''' IEnvelope env = new EnvelopeClass();
''' env.SpatialReference = base.m_spRef;
''' IPoint point = new PointClass();
''' point.SpatialReference = m_spRef;
''' foreach (DataRow r in m_table.Rows)
''' {
''' point.Y = Convert.ToDouble(r["Y"]);
''' point.X = Convert.ToDouble(r["X"]);
'''
''' env.Union(point.Envelope);
''' }
'''
''' return env;
'''}
''' </code>
''' </remarks>
Public Overridable ReadOnly Property Extent() As IEnvelope Implements IGeoDataset.Extent
Get
Return m_extent
End Get
End Property
''' <summary>
''' The spatial reference of the underlying data.
''' </summary>
''' <remarks>The property must return the underlying data spatial reference and
''' must not reporoject it into the layer's spatial reference </remarks>
Public Overridable ReadOnly Property SpatialReference1() As ISpatialReference Implements IGeoDataset.SpatialReference ''ILayer.SpatialReference,
Get
Return m_spatialRef
End Get
End Property
#End Region
#Region "IPersistVariant Members"
''' <summary>
''' The ID of the object.
''' </summary>
Public Overridable ReadOnly Property ID() As UID Implements IPersistVariant.ID
Get
' TODO: Add clsCustomLayer.ID getter implementation
Return Nothing
End Get
End Property
''' <summary>
''' Loads the object properties from the stream.
''' </summary>
''' <param name="Stream"></param>
''' <remarks>The Load method must read the data from the stream in the same order the data was
''' written to the stream in the Save method.
''' Streams are sequential; you mut ensure that your data is saved and loaded in the correct order,
''' so that the correct data is written to the correct member.
''' </remarks>
Public Overridable Sub Load(ByVal Stream As IVariantStream) Implements IPersistVariant.Load
m_extensions = CType(Stream.Read(), ArrayList)
End Sub
''' <summary>
''' Saves the object properties to the stream.
''' </summary>
''' <param name="Stream"></param>
Public Overridable Sub Save(ByVal Stream As IVariantStream) Implements IPersistVariant.Save
Stream.Write(m_extensions)
End Sub
#End Region
#Region "ILayer Members"
#Region "Properties"
''' <summary>
''' Indicates if the layer shows map tips.
''' </summary>
''' <remarks>Indicates whether or not map tips are shown for the layer.
''' If set to True, then map tips will be shown for the layer.
''' You can determine the text that will be shown via TipText.
'''</remarks>
Public Overridable Property ShowTips() As Boolean Implements ILayer.ShowTips
Get
Return m_ShowTips
End Get
Set(ByVal value As Boolean)
m_ShowTips = value
End Set
End Property
''' <summary>
''' The default area of interest for the layer. Returns the spatial-referenced extent of the layer.
''' </summary>
Public Overridable ReadOnly Property AreaOfInterest() As IEnvelope Implements ILayer.AreaOfInterest
Get
Return m_extent
End Get
End Property
''' <summary>
''' Indicates if the layer is currently visible.
''' </summary>
Public Overridable Overloads Property Visible() As Boolean Implements ILayer.Visible
Get
Return m_visible
End Get
Set(ByVal value As Boolean)
m_visible = value
End Set
End Property
''' <summary>
''' Indicates if the layer needs its own display cache.
''' </summary>
''' <remarks>This property indicates whether or not the layer requires its own display cache.
''' If this property is True, then the Map will use a separate display cache for the layer so
''' that it can be refreshed indpendently of other layers.</remarks>
Public Overridable Property Cached() As Boolean Implements ILayer.Cached
Get
Return m_IsCached
End Get
Set(ByVal value As Boolean)
m_IsCached = value
End Set
End Property
''' <summary>
''' Minimum scale (representative fraction) at which the layer will display.
''' </summary>
''' <remarks>Specifies the minimum scale at which the layer will be displayed.
''' This means that if you zoom out beyond this scale, the layer will not display.
''' For example, specify 1000 to have the layer not display when zoomed out beyond 1:1000.</remarks>
Public Overridable Property MinimumScale() As Double Implements ILayer.MinimumScale
Get
Return m_MinimumScale
End Get
Set(ByVal value As Double)
m_MinimumScale = value
End Set
End Property
''' <summary>
''' Indicates if the layer is currently valid.
''' </summary>
''' <remarks>The valid property indicates if the layer is currently valid.
''' Layers that reference feature classes are valid when they hold a reference to a valid feature class.
''' The property does not however validate the integrity of the feature classes reference to the database.
''' Therefore, in rare situations if a datasource is removed after a layer is initialized,
''' the layer will report itself as valid but query attempts to the data source will error due to the lack
''' of underlying data.</remarks>
Public Overridable ReadOnly Property Valid() As Boolean Implements ILayer.Valid
Get
Return m_bValid
End Get
End Property
''' <summary>
''' The Layer name.
''' </summary>
Public Overridable Overloads Property Name() As String Implements ILayer.Name
Get
Return m_sName
End Get
Set(ByVal value As String)
m_sName = value
End Set
End Property
''' <summary>
''' Maximum scale (representative fraction) at which the layer will display.
''' </summary>
''' <remarks>Specifies the maximum scale at which the layer will be displayed.
''' This means that if you zoom in beyond this scale, the layer will not display.
''' For example, specify 500 to have the layer not display when zoomed in beyond 1:500.</remarks>
Public Overridable Property MaximumScale() As Double Implements ILayer.MaximumScale
Get
Return m_MaximumScale
End Get
Set(ByVal value As Double)
m_MaximumScale = value
End Set
End Property
''' <summary>
''' Supported draw phases.
''' </summary>
''' <remarks>Indicates the draw phases supported by the layer (esriDPGeography, esriDPAnnotation,
''' esriDPSelection, or any combination of the three).
''' The supported draw phases are defined by esriDrawPhase.
''' When multiple draw phases are supported, the sum of the constants is used.
''' For example, if SupportedDrawPhases = 3 then the layer supports drawing in the geography and annotation phases.</remarks>
Public ReadOnly Property SupportedDrawPhases() As Integer Implements ILayer.SupportedDrawPhases
Get
Return CInt(esriDrawPhase.esriDPGeography)
End Get
End Property
''' <summary>
''' Spatial reference for the layer.
''' </summary>
'''<remarks>This property is only used for map display, setting this property does not
'''change the spatial reference of the layer's underlying data.
'''The ArcGIS framework uses this property to pass the spatial reference from the map
'''to the layer in order to support on-the-fly projection.</remarks>
Private WriteOnly Property SpatialReference() As ISpatialReference Implements ESRI.ArcGIS.Carto.ILayer.SpatialReference
Set(ByVal value As ISpatialReference)
m_spatialRef = value
End Set
End Property
''' <summary>
''' Map tip text at the specified location.
''' </summary>
''' <param name="X"></param>
''' <param name="Y"></param>
''' <param name="Tolerance"></param>
''' <returns>The text string that gets displayed as a map tip if ShowTips = true.</returns>
Public Overridable ReadOnly Property TipText(ByVal X As Double, ByVal Y As Double, ByVal Tolerance As Double) As String Implements ILayer.TipText
Get
Return Nothing
End Get
End Property
#End Region
#Region "Methods"
''' <summary>
''' Draws the layer to the specified display for the given draw phase.
''' </summary>
''' <param name="drawPhase"></param>
''' <param name="Display"></param>
''' <param name="trackCancel"></param>
''' <remarks>This method draws the layer to the Display for the specified DrawPhase.
''' Use the TrackCancel object to allow the drawing of the layer to be interrupted by the user.
''' In order to implement you inheriting class, you must override this method</remarks>
Public Sub Draw(ByVal drawPhase As esriDrawPhase, ByVal Display As IDisplay, ByVal trackCancel As ITrackCancel) Implements ILayer.Draw
End Sub
#End Region
#End Region
#Region "IDynamicLayer Members"
''' <summary>
''' The dynamic layer draw method
''' </summary>
''' <param name="DynamicDrawPhase">the current drawphase of the drawing</param>
''' <param name="Display">the ActiveView's display</param>
''' <param name="DynamicDisplay">the ActiveView's dynamic display</param>
''' <remarks>This method is set as abstract, which means that the inherited class must override it</remarks>
Public MustOverride Sub DrawDynamicLayer(ByVal DynamicDrawPhase As esriDynamicDrawPhase, ByVal Display As IDisplay, ByVal DynamicDisplay As IDynamicDisplay) Implements IDynamicLayer.DrawDynamicLayer
''' <summary>
''' set the dirty flag of the layer
''' </summary>
''' <param name="DynamicDrawPhase"></param>
Public Property DynamicLayerDirty(ByVal DynamicDrawPhase As ESRI.ArcGIS.Display.esriDynamicDrawPhase) As Boolean Implements ESRI.ArcGIS.Carto.IDynamicLayer.DynamicLayerDirty
Get
Select Case DynamicDrawPhase
Case esriDynamicDrawPhase.esriDDPCompiled
Return m_bIsCompiledDirty
Case esriDynamicDrawPhase.esriDDPImmediate
Return m_bIsImmediateDirty
End Select
Return False
End Get
Set(ByVal value As Boolean)
Select Case DynamicDrawPhase
Case esriDynamicDrawPhase.esriDDPCompiled
m_bIsCompiledDirty = value
Case esriDynamicDrawPhase.esriDDPImmediate
m_bIsImmediateDirty = value
End Select
End Set
End Property
''' <summary>
''' Return the rate in which display lists gets recompiled. This is only relevant
''' for items that gets drawn using the 'esriDynamicDrawPhase.esriDDPCompiled' drawphase.
''' </summary>
Public ReadOnly Property DynamicRecompileRate() As Integer Implements IDynamicLayer.DynamicRecompileRate
Get
Return m_nDynamicRecompileRate
End Get
End Property
#End Region
#Region "ILayerGeneralProperties Members"
''' <summary>
''' Last maximum scale setting used by layer.
''' </summary>
Public Overridable ReadOnly Property LastMaximumScale() As Double Implements ILayerGeneralProperties.LastMaximumScale
Get
Return 0
End Get
End Property
''' <summary>
''' Last minimum scale setting used by layer.
''' </summary>
Public Overridable ReadOnly Property LastMinimumScale() As Double Implements ILayerGeneralProperties.LastMinimumScale
Get
Return 0
End Get
End Property
''' <summary>
''' Description for the layer.
''' </summary>
Public Overridable Property LayerDescription() As String Implements ILayerGeneralProperties.LayerDescription
Get
Return Nothing
End Get
Set(ByVal value As String)
End Set
End Property
#End Region
#Region "ILayerExtensions Members"
''' <summary>
''' Removes the specified extension.
''' </summary>
''' <param name="Index"></param>
'Public Overridable Sub RemoveExtension(ByVal Index As Integer)
Public Sub RemoveExtension(ByVal Index As Integer) Implements ESRI.ArcGIS.Carto.ILayerExtensions.RemoveExtension
If Index < 0 Or Index > m_extensions.Count - 1 Then
Return
End If
m_extensions.RemoveAt(Index)
End Sub
''' <summary>
''' Number of extensions.
''' </summary>
Public ReadOnly Property ExtensionCount() As Integer Implements ESRI.ArcGIS.Carto.ILayerExtensions.ExtensionCount
Get
Return m_extensions.Count
End Get
End Property
''' <summary>
''' Adds a new extension.
''' </summary>
''' <param name="ext"></param>
Public Sub AddExtension(ByVal ext As Object) Implements ESRI.ArcGIS.Carto.ILayerExtensions.AddExtension
If ext Is Nothing Then
Return
End If
m_extensions.Add(ext)
End Sub
''' <summary>
''' The extension at the specified index.
''' </summary>
''' <param name="Index"></param>
Public ReadOnly Property Extension(ByVal Index As Integer) As Object Implements ESRI.ArcGIS.Carto.ILayerExtensions.Extension
Get
If Index < 0 Or Index > m_extensions.Count - 1 Then
Return Nothing
End If
Return m_extensions(Index)
End Get
End Property
#End Region
#Region "Data Structure basic functionality"
''' <summary>
''' Create a new item (does not add it to the layer)
''' </summary>
''' <returns></returns>
Public Overridable Function NewItem() As DataRow
Return m_table.NewRow()
End Function
''' <summary>
''' Add an item to the layer
''' </summary>
''' <param name="row"></param>
Public Overridable Sub AddItem(ByVal row As DataRow)
m_table.Rows.Add(row)
End Sub
''' <summary>
''' Add an item to the Layer
''' </summary>
''' <param name="values"></param>
Public Overridable Sub AddItem(ByVal values As Object())
m_table.Rows.Add(values)
End Sub
''' <summary>
''' Query for items in the layer
''' </summary>
''' <param name="queryFilter">WHERE clause</param>
''' <returns></returns>
Public Overridable Overloads Function [Select](ByVal queryFilter As String) As DataRow()
Return m_table.Select(queryFilter)
End Function
''' <summary>
''' Remove all items in the layer
''' </summary>
Public Overridable Sub Clear()
m_table.Rows.Clear()
End Sub
''' <summary>
''' Remove the item from the layer
''' </summary>
''' <param name="row">The row to remove</param>
Public Overridable Sub RemoveItem(ByVal row As DataRow)
m_table.Rows.Remove(row)
End Sub
'indexer. Pass an index and return a record
Default Public ReadOnly Property Item(ByVal index As Integer) As DataRow
Get
Return m_table.Rows(index)
End Get
End Property
''' <summary>
''' return the number of geometries in the layer
''' </summary>
Public ReadOnly Property NumOfRecords() As Integer
Get
Return m_table.Rows.Count
End Get
End Property
#End Region
#Region "IEnumerable Members"
''' <summary>
''' Allow users to directly enumerate through the layer's records
''' </summary>
''' <returns></returns>
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return m_table.Rows.GetEnumerator()
End Function
#End Region
#Region "IDisposable Members"
''' <summary>
''' Dispose the layer
''' </summary>
Public Shadows Sub Dispose() Implements IDisposable.Dispose
m_extent = Nothing
m_spatialRef = Nothing
MyBase.Dispose()
End Sub
#End Region
End Class