I am currently working on a project where when user loads up their map (mxd) into our system, we create several custom featuerlayers for them. My problem is though, I have no idea how to check if I have ALREADY created those layers already (say user loads up mxd, layers created, save, re-load the mxd, should verify if layers already exists).
Is there a Unique Id for a FeatuerLayerClass in ArcEngine10, there are OIDName, and ObjectClassID in FeatureLayerClass.FeatureClass, but those don't seem to work (cannot assign ObjectClassId, and want to use UniqueId for OIDName)?
I created my layer as featurelayerclass business object like this.
Code:
/// <summary>
/// Unique Route LayerId
/// </summary>
public static Guid RouteFeatureLayerId
{
get { return Guid.Parse("ba25a332-0e48-4ce5-a4c5-38dc36c0700c"); }
}
/// <summary>
/// Feature class that stores info on the routes
/// </summary>
public FeatureLayerClass RouteFeatureLayer
{
get
{
if (_routeFeatureClass == null)
{
IPropertySet property = new PropertySetClass();
property.SetProperty("Id", RouteFeatureLayerId);
_routeFeatureClass = new FeatureLayerClass();
_routeFeatureClass.FeatureClass = CreateFeatureClass(Workspace, null, ShapeType.Polylines.ToString(), CreateFields(ShapeType.Polylines, FeatureLayerType.Routes), null, null, "");
_routeFeatureClass.Name = "Routes";
_routeFeatureClass.Visible = true;
_routeFeatureClass.Cached = true;
_routeFeatureClass.AddExtension(property);
CustomLayers.Add(_routeFeatureClass);
}
return _routeFeatureClass;
}
set
{
_routeFeatureClass = value;
}
}
Creating workspace
/// <summary>
/// Create a workspace for the shapefile or geodatabase
/// </summary>
private IWorkspace CreateWorkspace(string workspaceType, string workspaceDirectory)
{
Type factoryType = null;
IWorkspaceFactory workspaceFactory = null;
switch (workspaceType)
{
case "Shapefile":
// Instantiate a Shapefile workspace factory
factoryType = Type.GetTypeFromProgID("esriDataSourcesFile.ShapefileWorkspaceFactory");
break;
case "PersonalGeodatabase":
// Instantiate an Access workspace factory
factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.AccessWorkspaceFactory");
break;
case "FileGeodatabase":
// Instantiate a file geodatabase workspace factory
factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
break;
}
workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);
//Create a directory hierarchy to seperate out datasets created for Points, Polylines, and Polygons
Directory.CreateDirectory(workspaceDirectory);
IWorkspaceName workspaceName = workspaceFactory.Create(workspaceDirectory + "\\", workspaceType, null, 0);
IName Name = (IName)workspaceName;
IWorkspace workspace = (IWorkspace)(Name.Open());
return workspace;
}
Creating FeatureClass
/// <summary>
/// Helper to create a Feature Class.
/// </summary>
private IFeatureClass CreateFeatureClass(IWorkspace workspace, IFeatureDataset featureDataset, string featureClassName, IFields fields, ESRI.ArcGIS.esriSystem.UID CLSID, ESRI.ArcGIS.esriSystem.UID CLSEXT, string configKeyword)
{
IFeatureClass featureClass = null;
IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)workspace; // Explicit Cast
string shapeFieldName = String.Empty;
try
{
if (featureClassName == "")
{
return null; // name was not passed in
}
//else if (((IWorkspace2)workspace).get_NameExists(esriDatasetType.esriDTFeatureClass, featureClassName))
//{
// featureClass = featureWorkspace.OpenFeatureClass(featureClassName); // feature class with that name already exists
// return featureClass;
//}
// assign the class id value if not assigned
if (CLSID == null)
{
CLSID = new ESRI.ArcGIS.esriSystem.UIDClass();
CLSID.Value = "esriGeoDatabase.Feature";
}
// locate the shape field
for (Int32 j = 0; j < fields.FieldCount; j++)
{
if (fields.get_Field(j).Type == esriFieldType.esriFieldTypeGeometry)
{
shapeFieldName = fields.get_Field(j).Name;
}
}
// finally create and return the feature class
if (featureDataset == null)
{
// if no feature dataset passed in, create at the workspace level
featureClass = featureWorkspace.CreateFeatureClass(featureClassName, fields, CLSID, CLSEXT, esriFeatureType.esriFTSimple, shapeFieldName, configKeyword);
}
else
{
featureClass = featureDataset.CreateFeatureClass(featureClassName, fields, CLSID, CLSEXT, esriFeatureType.esriFTSimple, shapeFieldName, configKeyword);
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.ToString());
Logger.Log.Debug(ex);
}
return featureClass;
}
Code to get layer
/// <summary>
/// Finds the layer
/// </summary>
/// <returns>the subcatchment layer</returns>
private IGeoFeatureLayer GetLayer(FeatureLayerClass featureLayer)
{
IGeoFeatureLayer layer = null;
ILayerExtensions layerExtension;
for (int x = 0; x < MapControl.LayerCount; x++)
{
layerExtension = ((ILayerExtensions)MapControl.get_Layer(x));
if (featureLayer.ExtensionCount > 0 && layerExtension.ExtensionCount > 0 &&
layerExtension.get_Extension(0) is PropertySetClass &&
featureLayer.get_Extension(0) is PropertySetClass &&
((PropertySetClass)layerExtension.get_Extension(0)).GetProperty("Id") == ((PropertySetClass)featureLayer.get_Extension(0)).GetProperty("Id"))
{
layer = MapControl.get_Layer(x) as IGeoFeatureLayer;
break;
}
}
return layer;
}
Thanks and Regards,
Kevin
Best Answer
Feature classes and object classes do have their ids, which are unique within a single geodatabase. This very often satisfies most scenarios similar to yours.
If you cannot uniquely identify a layer based on its feature class, you can leverage layer extensions to store arbitrary data with the layer.
A layer extension can be added to a layer via ILayerExtensions interface. Now, there is no common interface for layer extensions, but they typically implement some persistence through IPersistStream. Your layer extension would not do anything special but store some data by which you will uniquely identify your added layer.
So your task would be as follows:
I had a very similar problem and layers extensions turned out to be the best fit.
EDIT: below I post some code for a helper static class which allows you to quickly work with properties set inside a propertyset stored in the layer extension (.NET 3.5 or higher required). It takes care of accessing the extension object and creating it if not already assigned to the layer. It's used like this:
Instead of "SomeValue" you will probably generate and store some kind of layer identifier in there.
Here's the full source code for the
PropertySetLayerExtensionHelper
class: