How to persist data in a document


Summary
This topic shows how to persist data in an ArcGIS for Desktop application by implementing an extension.

The easiest and recommended way to persist data in a document is to build an add-in. For information on using add-ins, see Building add-ins for ArcGIS for Desktop.

Persisting data in a document

ArcGIS for Desktop applications use the compound document structure to persist the current state of non-geographic information system (GIS) data or objects used by an application when the document is saved. Persistence is used throughout the ArcGIS framework and extension is one of the objects that participates in the document persistence during the Save and Open events.
Supporting persistence is optional for extensions. Implement the IPersistVariant interface to support extension persistence in .NET.
Only extensions that have already been loaded in the application participate in the Save and Open events. Standard extensions are always loaded at startup, so they are guaranteed to be in the process; just-in-time (JIT) extensions, on the other hand, do not participate in the process unless they have been loaded.

Creating an extension with persistence

To create an extension with persistence, follow these steps:
  1. Create an extension class by implementing IExtension, IPersistVariant, and other optional interfaces by Using item templates to extend ArcObjects:
    1. Using the Application Extension item template under ArcGIS Desktop
      1. Select the Configurable Extension option (for example, Configurable Extension [ArcMap]). This extension class implements IExtension, IExtensionConfig, and IPersistVariant.
    2. Using the ArcGIS Add Class Wizard to extend ArcObjects:
      1. On the Base Implementation page, select Application Framework from the Customization group and Extension from the base component list. 
      2. On the Optional Interfaces page, add the ESRI.ArcGIS.esriSystem.IPersistVariant interface.
      3. Check the appropriate application component category for the extension on the Component Category page (for example, ArcMap Extension).
  2. Set the IExtension.Name property that is used to identify the extension class being persisted in the document. The length of the name must not exceed 31 characters.
  3. In the IPersistVariant.ID property, return the class identifier (CLSID) for the class.
  4. Determine what data should be persisted and how. Consider version compatibility to prepare for potential extension evolution over time or versions.
  5. Implement the IPersistVariant.Save method to write data when the document is saved.
    1. Use the IVariantStream.Write method of the input parameter to write data to the stream.
    2. If version compatibility is enforced, use either IDocumentVersion or your own internal persistence version number to mark the version.
  6. Implement the IPersistVariant.Load method by using the IVariantStream.Read method of the input parameter to read data when the document is opened.
    1. Streams are sequential, so you must use the same order to read from the stream as the data was written.
    2. If version compatibility is enforced, determine the persistence version to read the data correctly.
    3. Handle any exceptions and raise an appropriate error back to the application when necessary.
  7. In .NET, you must release the stream object using the System.Runtime.InteropServices.Marshal.ReleaseCOMObject method at the end of the Save and Load implementations.
See the following code example:
[C#]
namespace HowTo
{
    [ClassInterface(ClassInterfaceType.None)][Guid(
        "6de1d416-7a87-44b9-954a-cdd5e82ff998")]
    public class HowToExtension: IExtension, IPersistVariant
    {
        private string m_value1;
        private int m_value2;

        string IExtension.Name
        {
            get
            {
                return "HowToExtensionPersistence";
            }
        }
        void IExtension.Shutdown(){}
        void IExtension.Startup(ref object initializationData){}

        #region IPersistVariant Members
        public UID ID
        {
            get
            {
                UID typeID = new UIDClass();
                typeID.Value = GetType().GUID.ToString("B");
                return typeID;
            }
        }
        public void Load(IVariantStream Stream)
        {
            m_value1 = Convert.ToString(Stream.Read());
            m_value2 = Convert.ToInt32(Stream.Read());
            Marshal.ReleaseComObject(Stream);
        }

        public void Save(IVariantStream Stream)
        {
            Stream.Write(m_value1);
            Stream.Write(m_value2);
            Marshal.ReleaseComObject(Stream);
        }

        #endregion 
    }

}
[VB.NET]
<ComClass("cc9715ed-e54f-4c2b-ac76-308a1069cfca")> _
          Public Class HowToExtension
    Implements IExtension
    Implements IPersistVariant
    
    Private m_value1 As String
    Private m_value2 As Integer
    
    Public Sub New()
        MyBase.New()
    End Sub
    
    Public ReadOnly Property Name() As String Implements IExtension.Name
    Get
    Return "HowToExtensionPersistence"
    End Get
End Property

Public Sub Shutdown() Implements IExtension.Shutdown
End Sub

Public Sub Startup(ByRef initializationData As Object) Implements IExtension.Startup
End Sub

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

Public Sub Load(ByVal Stream As IVariantStream) Implements IPersistVariant.Load
    m_value1 = Convert.ToString(Stream.Read())
    m_value2 = Convert.ToInt32(Stream.Read())
    Marshal.ReleaseComObject(Stream)
End Sub

Public Sub Save(ByVal Stream As IVariantStream) Implements IPersistVariant.Save
    Stream.Write(m_value1)
    Stream.Write(m_value2)
    Marshal.ReleaseComObject(Stream)
End Sub

#End Region

End Class

What can be persisted?

You can persist any value type—string, number, and Boolean—directly in the stream. For reference type, you can persist the object in the stream directly if it implements persistence; for example, if it implements IPersist and IPersistStream or IPersistVariant. The Color object is an example. If the object does not implement persistence, you can write the members out individually and reconstruct the object during load.

Arrays

ESRI.ArcGIS.esriSystem.ArrayClass and .NET arrays cannot be persisted directly. You can either persist the count and value of each member individually or persist the members in an ESRI.ArcGIS.esriSystem.PropertySetClass object.

Custom components

Depending on the custom component implementation and the ArcGIS version your extension is to be installed with, different techniques are used to persist the components. For more information on backward compatibility, see IDocumentVersionSupportGEN.

Managing version compatibility

Depending on the ArcGIS version your extension is to be installed with and the document version to be worked against, your persistence code needs to adapt to the version compatibility policies. Version compatibility can be enforced by checking the document version of the input stream (cast it on IDocumentVersion) or managing your own as an internal version number.






To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):
Development licensing Deployment licensing
ArcGIS for Desktop Basic ArcGIS for Desktop Basic
ArcGIS for Desktop Standard ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced