Select to view content in your preferred language

event not firing at startup when extension is left on from previous session

979
4
06-15-2010 01:11 PM
CarlosPiccirillo
Emerging Contributor
I got my extension almost running perfectly by have one more hurdle to overcome. If the extension is turned off when ArcMap starts, the user can turn on/off the extension and all the code runs fine. My problem occurs when the user leaves the extension turned on, exists ArcMap and then starts ArcMap up again. When this happens, the extension is already checked on in the Extension Manager dialog and the code that I need to have run, does not fire because ArcMap is not totally loaded at the time (IApplicationStatus).

In the code below, CheckToolbarValidity has a couple of checks to verify that ArcMap is fully initialized and that the extension is turned on. If it passes these two checks, it calls SetupEvents which turns on the listeners for IActivewView::AddItem. Here lies my problem. If the extension is already turned on when ArcMap starts up, m_appStatus.Initialized returns false and the method exits before it can call SetupEvents.

My extension follows the AcmeExt ESRI sample pretty closely with the main difference being that I don't call SetupEvents from IExtension::Startup. The reason I don't do this is because if did, the event listener would be turned on every time ArcMap starts regardless if my extension was turned on or not.

I was thinking I could put a timer in CheckToolbarValidity so that it loops until m_appStatus.Initialized returns true. Problem here is that I never have tried to do timer in C# before.

Does anyone think this is a bad idea and if so, do you have a suggestion for how to get around my problem?

Thanks,
Carlos

   public class Extension : IExtension, IExtensionConfig, IPersistVariant
    {
        private IApplication m_application;
        private IMxDocument m_mxDocument;
        private esriExtensionState m_extensionState = esriExtensionState.esriESDisabled;
        private IApplicationStatus m_appStatus;
        private IApplicationStatusEvents_Event m_mapStatusEvents;
        private IActiveViewEvents_Event m_mapEvents;

        #region IExtension Members

        /// <summary>
        /// Name of extension. Do not exceed 31 characters
        /// </summary>
        public string Name
        {
            get
            {
                return "RegGSS Extension";
            }
        }

        public void Shutdown()
        {
            m_application = null;
        }

        public void Startup(ref object initializationData)
        {
            m_application = initializationData as IApplication;
            if (m_application == null)
                return;

            m_appStatus = m_application as IApplicationStatus;
        }

        #endregion

        #region IExtensionConfig Members

        public string Description
        {
            get
            {
                return "RegGSS 9.3\r\n" +
                       "Copyright © SFWMD 2010\r\n\r\n" +
                       "Environmental Resource Regulation\r\n" +
                       "Regulatory Support - GIS Section";
            }
        }

        /// <summary>
        /// Friendly name shown in the Extension dialog
        /// </summary>
        public string ProductName
        {
            get
            {
                return "RegGSS";
            }
        }

        public esriExtensionState State
        {
            get
            {
                return m_extensionState;
            }
            set
            {
                if (m_extensionState != 0 && value == m_extensionState)
                    return;

                //Check if ok to enable or disable extension
                esriExtensionState requestState = value;
                if (requestState == esriExtensionState.esriESEnabled)
                {
                    //Cannot enable if it's already in unavailable state
                    if (m_extensionState == esriExtensionState.esriESUnavailable)
                    {
                        throw new COMException("Cannot enable extension");
                    }

                    //Determine if state can be changed
                    esriExtensionState checkState = StateCheck(true);
                    m_extensionState = checkState;

                    CheckToolbarValidity();
                }
                else if (requestState == 0 || requestState == esriExtensionState.esriESDisabled)
                {
                    //Determine if state can be changed
                    esriExtensionState checkState = StateCheck(false);
                    if (checkState != m_extensionState)
                        m_extensionState = checkState;

                    MessageBox.Show("Disabled");
                    UnloadEvents();
                }
            }
        }

        #endregion

        /// <summary>
        /// Determine extension state 
        /// </summary>
        /// <param name="requestEnable">true if to enable; false to disable</param>
        private esriExtensionState StateCheck(bool requestEnable)
        {
            //Turn on or off extension directly
            if (requestEnable)
                return esriExtensionState.esriESEnabled;
            else
                return esriExtensionState.esriESDisabled;
        }

        private void SetupEvents()
        {
            // Make sure we're dealing with ArcMap
            if (m_application.Document.Parent is IMxApplication)
            {
                m_mxDocument = m_application.Document as IMxDocument;
                m_mapEvents = m_mxDocument.FocusMap as IActiveViewEvents_Event;
                m_mapEvents.ItemAdded += new IActiveViewEvents_ItemAddedEventHandler(OnItemAdded);

                m_mapStatusEvents = m_application.Document.Parent as IApplicationStatusEvents_Event;
                m_mapStatusEvents.Initialized += new IApplicationStatusEvents_InitializedEventHandler(OnInitialized);
            }
        }

        // Called when the framework is fully initialized
        // After this event fires, it is safe to make UI customizations
        void OnInitialized()
        {
            CheckToolbarValidity();
        }

        void OnItemAdded(object Item)
        {
            //MessageBox.Show("Item Added");

            IFeatureLayer pFeatureLayer;
            if (Item is IFeatureLayer)
            {
                pFeatureLayer = Item as IFeatureLayer;
                MessageBox.Show("Layer name: " + pFeatureLayer.Name);
            }
        }

        private void CheckToolbarValidity()
        {
            // Wait for framework to initialize before making UI customizations
            // Check framework initialization flag
            if (!m_appStatus.Initialized)
                return;

            // Make sure the extension is enabled
            if (m_extensionState != esriExtensionState.esriESEnabled)
                return;

            SetupEvents();
        }

        private void UnloadEvents()
        {
            //m_mapEvents.ItemAdded -= new IActiveViewEvents_ItemAddedEventHandler(OnItemAdded);
        }
    }
 
0 Kudos
4 Replies
KenBuja
MVP Esteemed Contributor
In the extension I developed, I used the same ESRI example as you did. One thing that is different between our code is when you initialize the variable m_extensionState. When you initialize it, you're also setting it to disabled. In my code, the variable gets set to either disabled or enabled in the State Property.
0 Kudos
CarlosPiccirillo
Emerging Contributor
Ken,

Thanks for the reply!

Being that this is my first attempt at writing an extension, I am trying to follow an ESRI example as closely as possible because I still don't understand everything that is going on in the code. In their example, they initialize m_extensionState at the top so I left it there. I tried to not setting it to a value at the start (private esriExtensionState m_extensionState) and that caused another problem. If I didn't set m_extensionState to disabled at the start, the else if disabled code would run in the state property regardless if the extension was checked on or off in the extension manager.

Could you send me your code so I can see where you are setting m_extensionState?

Thanks,
Carlos

In the extension I developed, I used the same ESRI example as you did. One thing that is different between our code is when you initialize the variable m_extensionState. When you initialize it, you're also setting it to disabled. In my code, the variable gets set to either disabled or enabled in the State Property.
0 Kudos
KenBuja
MVP Esteemed Contributor
Here's the VB.NET code for my extension

Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.esriSystem
Imports System.Runtime.InteropServices
Imports ESRI.ArcGIS.Framework

<ComClass(Extension.ClassId, Extension.InterfaceId, Extension.EventsId), _
 ProgId("HabitatDigitizer_92.Extension")> _
Public Class Extension
  Implements IExtension
  Implements IExtensionConfig
  Implements IPersistVariant

#Region "COM Registration Function(s)"
  <ComRegisterFunction(), ComVisibleAttribute(False)> _
  Public Shared Sub RegisterFunction(ByVal registerType As Type)
    ' Required for ArcGIS Component Category Registrar support
    ArcGISCategoryRegistration(registerType)

    'Add any COM registration code after the ArcGISCategoryRegistration() call

  End Sub

  <ComUnregisterFunction(), ComVisibleAttribute(False)> _
  Public Shared Sub UnregisterFunction(ByVal registerType As Type)
    ' Required for ArcGIS Component Category Registrar support
    ArcGISCategoryUnregistration(registerType)

    'Add any COM unregistration code after the ArcGISCategoryUnregistration() call

  End Sub

#Region "ArcGIS Component Category Registrar generated code"
  ''' <summary>
  ''' Required method for ArcGIS Component Category registration -
  ''' Do not modify the contents of this method with the code editor.
  ''' </summary>
  Private Shared Sub ArcGISCategoryRegistration(ByVal registerType As Type)
    Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
    MxExtension.Register(regKey)

  End Sub
  ''' <summary>
  ''' Required method for ArcGIS Component Category unregistration -
  ''' Do not modify the contents of this method with the code editor.
  ''' </summary>
  Private Shared Sub ArcGISCategoryUnregistration(ByVal registerType As Type)
    Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
    MxExtension.Unregister(regKey)

  End Sub

#End Region
#End Region

#Region "COM GUIDs"
  ' These  GUIDs provide the COM identity for this class 
  ' and its COM interfaces. If you change them, existing 
  ' clients will no longer be able to access the class.
  Public Const ClassId As String = "85653ca9-ea9e-4c4a-894c-3a263c12e509"
  Public Const InterfaceId As String = "4326fdc0-a7bb-4f21-8f0b-f03d0caec6c0"
  Public Const EventsId As String = "940f2b66-d7b2-44bb-9025-4a1c380c98aa"
#End Region

  Private m_application As IApplication
  Private m_enableState As esriExtensionState

  ' A creatable COM class must have a Public Sub New() 
  ' with no parameters, otherwise, the class will not be 
  ' registered in the COM registry and cannot be created 
  ' via CreateObject.
  Public Sub New()
    MyBase.New()
  End Sub

  ''' <summary>
  ''' Determine extension state
  ''' </summary>
  Private Function StateCheck(ByVal requestEnable As Boolean) As esriExtensionState
    'TODO: Replace with advanced extension state checking if needed
    'Turn on or off extension directly 
    If requestEnable Then
      Return esriExtensionState.esriESEnabled
    Else
      Return esriExtensionState.esriESDisabled
    End If
  End Function

#Region "IExtension Members"
  ''' <summary>
  ''' Name of extension. Do not exceed 31 characters
  ''' </summary>
  Public ReadOnly Property Name() As String Implements ESRI.ArcGIS.esriSystem.IExtension.Name
    Get
      Return "Habitat Digitizer Extension"
    End Get
  End Property

  Public Sub Shutdown() Implements ESRI.ArcGIS.esriSystem.IExtension.Shutdown
    'TODO: Clean up resources

    m_application = Nothing
  End Sub

  Public Sub Startup(ByRef initializationData As Object) Implements ESRI.ArcGIS.esriSystem.IExtension.Startup
    m_application = CType(initializationData, IApplication)
    If m_application Is Nothing Then Return

    'TODO: Add code to initialize the extension
  End Sub
#End Region

#Region "IExtensionConfig Members"
  Public ReadOnly Property Description() As String Implements ESRI.ArcGIS.esriSystem.IExtensionConfig.Description
    Get
      'TODO: Replace description (use \r\n for line break)
      Return "Habitat Digitizer 5.0" & vbCrLf & "NOAA/NOS/NCCOS/CCMA/Biogeography Program" & vbCrLf & vbCrLf & "Provides tools to simplify the digitizing attribution process."
    End Get
  End Property

  ''' <summary>
  ''' Friendly name shown in the Extensions dialog
  ''' </summary>
  Public ReadOnly Property ProductName() As String Implements ESRI.ArcGIS.esriSystem.IExtensionConfig.ProductName
    Get
      'TODO:Replace()
      Return "Habitat Digitizer Extension"
    End Get
  End Property

  Public Property State() As ESRI.ArcGIS.esriSystem.esriExtensionState Implements ESRI.ArcGIS.esriSystem.IExtensionConfig.State
    Get
      Return m_enableState
    End Get
    Set(ByVal value As ESRI.ArcGIS.esriSystem.esriExtensionState)
      'If m_enableState <> 0 Or value = m_enableState Then Exit Property
      If value = m_enableState Then Exit Property

      'Check if ok to enable or disable extension
      Dim requestState As esriExtensionState = value
      If requestState = esriExtensionState.esriESEnabled Then
        'Cannot enable if it's already in unavailable state
        If m_enableState = esriExtensionState.esriESUnavailable Then
          Throw New COMException("Cannot enable extension")
        End If

        'Determine if state can be changed
        Dim checkState As esriExtensionState = StateCheck(True)
        m_enableState = checkState
      ElseIf requestState = esriExtensionState.esriESDisabled Then
        'Determine if state can be changed
        Dim checkState As esriExtensionState = StateCheck(False)
        If (m_enableState <> checkState) Then m_enableState = checkState
      End If
    End Set
  End Property
#End Region

#Region "IPersistVariant Members"
  Public ReadOnly Property ID() As ESRI.ArcGIS.esriSystem.UID Implements ESRI.ArcGIS.esriSystem.IPersistVariant.ID
    Get
      Dim typeID As UID = New UIDClass()
      typeID.Value = Me.GetType().GUID.ToString("B")
      Return typeID
    End Get
  End Property

  Public Sub Load(ByVal Stream As ESRI.ArcGIS.esriSystem.IVariantStream) Implements ESRI.ArcGIS.esriSystem.IPersistVariant.Load
    'TODO: Load persisted data from document stream

    Dim HDXTest As String
    Dim Count As Integer
    Dim Key As Object
    Dim ItemList() As Object
    Dim ListCount As Integer

    Try
      HDXTest = Stream.Read
      While Not HDXTest Is Nothing
        If HDXTest <> "HDX Stream" Then
          System.Windows.Forms.MessageBox.Show("The classification scheme and settings in this project cannot be read and must be reloaded manually.", "Cannot load settings", Windows.Forms.MessageBoxButtons.OK, Windows.Forms.MessageBoxIcon.Exclamation)
          Exit Sub
        Else
          Exit While
        End If
        HDXTest = Stream.Read
      End While

      Count = Stream.Read

      If Not theDict Is Nothing Then If theDict.ContainsKey("HDX.Classification Name") Then theDict.Clear()

      For i As Integer = 1 To Count
        Key = Stream.Read
        ListCount = Stream.Read
        ReDim ItemList(ListCount)
        For j As Integer = 0 To ListCount
          ItemList(j) = Stream.Read
        Next

        theDict.Add(Key, ItemList)
      Next

      'If Count > 0 Then createrenderer()

    Catch ex As Exception
      ExceptionMessage(ex, "Extension: IPersist_Load")
    End Try

    Marshal.ReleaseComObject(Stream)
  End Sub

  Public Sub Save(ByVal Stream As ESRI.ArcGIS.esriSystem.IVariantStream) Implements ESRI.ArcGIS.esriSystem.IPersistVariant.Save
    'TODO: Save extension related data to document stream

    Dim Count As Integer
    Dim ItemList() As Object

    Try

      Count = theDict.Count
      If theDict.ContainsKey("HDX.Point Legend") Then Count -= 1
      If theDict.ContainsKey("HDX.Line Legend") Then Count -= 1
      If theDict.ContainsKey("HDX.Polygon Legend") Then Count -= 1

      Stream.Write("HDX Stream")
      Stream.Write(Count)

      For Each Key As Object In theDict.Keys
        If InStr(Key, "Legend") = 0 Then
          ItemList = theDict.Item(Key)
          Stream.Write(Key)
          Count = ItemList.GetUpperBound(0)
          Stream.Write(Count)
          For i As Integer = 0 To Count
            Stream.Write(ItemList(i))
          Next
        End If
      Next

    Catch ex As Exception
      ExceptionMessage(ex, "Extension: IPersist_Save")
    End Try

    Marshal.ReleaseComObject(Stream)
  End Sub
#End Region

End Class



0 Kudos
CarlosPiccirillo
Emerging Contributor
Thanks Ken,

I'll try to make sense of it all and give it a try. I'll let you know what happens.

Carlos
0 Kudos