Wie überprüfe ich, ob bereits ein FeatureLayer vorhanden ist?

9

Ich arbeite derzeit an einem Projekt, bei dem Benutzer, wenn sie ihre Karte (mxd) in unser System laden, mehrere benutzerdefinierte Funktionen für sie erstellen. Mein Problem ist jedoch, dass ich keine Ahnung habe, wie ich überprüfen soll, ob ich diese Ebenen bereits erstellt habe (sagen wir, der Benutzer lädt mxd, erstellte Ebenen, speichert, lädt die mxd erneut, sollte überprüfen, ob bereits Ebenen vorhanden sind).

Gibt es eine eindeutige ID für eine FeatuerLayerClass in ArcEngine10, gibt es OIDName und ObjectClassID in FeatureLayerClass.FeatureClass, aber diese scheinen nicht zu funktionieren (können ObjectClassId nicht zuweisen und möchten UniqueId für OIDName verwenden)?

Ich habe meine Ebene als solches Geschäftsobjekt der Klassenklasse erstellt.

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;
        }
    }

Arbeitsbereich erstellen

    /// <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;

}

FeatureClass erstellen

        /// <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 zum Abrufen der Ebene

            /// <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;
            }

Danke und Grüße, Kevin

Kev84
quelle

Antworten:

7

Feature-Classes und Objektklassen haben ihre IDs, die innerhalb einer einzelnen Geodatabase eindeutig sind. Dies erfüllt sehr oft die meisten ähnlichen Szenarien wie Sie.

Wenn Sie einen Layer anhand seiner Feature-Class nicht eindeutig identifizieren können, können Sie Layer-Erweiterungen nutzen, um beliebige Daten mit dem Layer zu speichern.

Eine Layer-Erweiterung kann einem Layer über die ILayerExtensions- Schnittstelle hinzugefügt werden. Jetzt gibt es keine gemeinsame Schnittstelle für Layer-Erweiterungen, aber sie implementieren normalerweise eine gewisse Persistenz über IPersistStream . Ihre Ebenenerweiterung würde nichts Besonderes tun, sondern einige Daten speichern, anhand derer Sie Ihre hinzugefügte Ebene eindeutig identifizieren können.

Ihre Aufgabe wäre also wie folgt:

  • Erstellen Sie eine COM-Klasse, in der Ihr Flag (oder eine Art generierte ID) gespeichert wird. Implementieren Sie IPersistStream für diese Klasse. BEARBEITEN: Sie können problemlos ein PropertySet als Layer-Erweiterungsobjekt verwenden, anstatt eine eigene Klasse zu erstellen.
  • Wenn Sie einen Layer hinzufügen, durchlaufen Sie alle Layer in der Karte und prüfen Sie, ob einem dieser Layer Ihre Layer-Erweiterung mit den erwarteten gespeicherten Daten zugewiesen ist.
  • Wenn dies der Fall ist, fügen Sie die Ebene nicht hinzu, da sie bereits vorhanden ist.
  • Wenn nicht, fügen Sie die Ebene hinzu und fügen Sie über ILayerExtensions eine Instanz Ihrer Ebenenerweiterung hinzu.

Ich hatte ein sehr ähnliches Problem und Ebenenerweiterungen erwiesen sich als die beste Lösung.

BEARBEITEN: Im Folgenden werde ich Code für eine statische Hilfsklasse veröffentlichen, mit der Sie schnell mit Eigenschaften arbeiten können, die in einem in der Layer-Erweiterung gespeicherten Eigenschaftssatz festgelegt sind (.NET 3.5 oder höher erforderlich). Es kümmert sich darum, auf das Erweiterungsobjekt zuzugreifen und es zu erstellen, wenn es nicht bereits der Ebene zugewiesen ist. Es wird so verwendet:

        // 1) is a particular property ("MY.KEY") set on a layer?
        var isPropertySet = PropertySetLayerExtensionHelper.ExtensionPropertySetContainsKey(layer, "MY.KEY");

        // 2) set a property with a value on the layer:
        PropertySetLayerExtensionHelper.ExtensionPropertySetSetValueForKey(layer, "MY.KEY", "SomeValue");

        // 3) retrieve a value for the given key stored at some point before:
        var value = PropertySetLayerExtensionHelper.ExtensionPropertySetGetValueForKey(layer, "MY.KEY");

Anstelle von "SomeValue" werden Sie dort wahrscheinlich eine Art Layer-ID generieren und speichern.

Hier ist der vollständige Quellcode für die PropertySetLayerExtensionHelperKlasse:

public static class PropertySetLayerExtensionHelper
{
    /// <summary>
    /// Returns whether the property set stored in the layer extensions contains a value for the given key.
    /// </summary>
    /// <param name="layer">The layer.</param>
    /// <param name="key">The key.</param>
    /// <returns>Whether the property set stored in the layer extensions contains a value for the given key.</returns>
    public static bool ExtensionPropertySetContainsKey(ILayer layer, string key)
    {
        if (layer == null) throw new ArgumentNullException("layer");
        if (key == null) throw new ArgumentNullException("key");

        var propertySet = GetPropertySetInLayerExtension(layer);
        return propertySet != null
            && propertySet.AsEnumerable().Any(pair => pair.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
    }

    /// <summary>
    /// Returns the value for the given key from the property set stored in the layer extension or <b>null</b>
    /// if no such key is present.
    /// </summary>
    /// <param name="layer">The layer.</param>
    /// <param name="key">The key.</param>
    /// <returns>The value for the given key from the property set stored in the layer extension or <b>null</b>
    /// if no such key is present.</returns>
    public static object ExtensionPropertySetGetValueForKey(ILayer layer, string key)
    {
        if (layer == null) throw new ArgumentNullException("layer");
        if (key == null) throw new ArgumentNullException("key");

        var propertySet = GetPropertySetInLayerExtension(layer);
        if (propertySet == null) return null;

        return propertySet.AsEnumerable()
            .Where(p => p.Key.Equals(key, StringComparison.OrdinalIgnoreCase))
            .Select(p => p.Value)
            .FirstOrDefault();
    }

    /// <summary>
    /// Sets the value for the given key in the property set stored in a layer extension. If there is
    /// no property set among the layer's extensions, it is created and assigned to the layer.
    /// </summary>
    /// <param name="layer">The layer.</param>
    /// <param name="key">The key.</param>
    /// <param name="value">The value for the given key.</param>
    public static void ExtensionPropertySetSetValueForKey(ILayer layer, string key, object value)
    {
        if (layer == null) throw new ArgumentNullException("layer");
        if (key == null) throw new ArgumentNullException("key");

        var propertySet = GetOrCreatePropertySetInLayerExtension(layer);
        if (propertySet == null)
        {
            throw new InvalidOperationException("The given layer does not support layer extensions.");
        }

        propertySet.SetProperty(key, value);
    }

    /// <summary>
    /// Returns a property set from a layer extension.
    /// </summary>
    /// <param name="layer">The layer.</param>
    /// <returns>A property set from a layer extension.</returns>
    public static IPropertySet GetPropertySetInLayerExtension(ILayer layer)
    {
        if (layer == null) throw new ArgumentNullException("layer");

        var layerExtensions = layer as ILayerExtensions;
        if (layerExtensions == null)
        {
            return null;
        }

        var propertySetExtension = layerExtensions.AsEnumerable().OfType<IPropertySet>().FirstOrDefault();
        return propertySetExtension;
    }

    /// <summary>
    /// Returns a property set from a layer extension. If not set on the layer,
    /// the property set is created and assigned to it.
    /// </summary>
    /// <param name="layer">The layer.</param>
    /// <returns>A property set from a layer extension.</returns>
    public static IPropertySet GetOrCreatePropertySetInLayerExtension(ILayer layer)
    {
        if (layer == null) throw new ArgumentNullException("layer");

        var propertySet = GetPropertySetInLayerExtension(layer);
        if (propertySet != null)
        {
            return propertySet;
        }

        var layerExtensions = layer as ILayerExtensions;
        if (layerExtensions == null)
        {
            return null;
        }

        propertySet = new PropertySetClass();
        layerExtensions.AddExtension(propertySet);
        return propertySet;
    }

    private static IEnumerable<object> AsEnumerable(this ILayerExtensions layerExtensions)
    {
        if (layerExtensions == null) throw new ArgumentNullException("layerExtensions");

        for (var i = 0; i < layerExtensions.ExtensionCount; i++)
        {
            yield return layerExtensions.get_Extension(i);
        }
    }

    private static IEnumerable<KeyValuePair<string, object>> AsEnumerable(this IPropertySet propertySet)
    {
        if (propertySet == null) throw new ArgumentNullException("propertySet");
        if (propertySet.Count == 0) yield break;

        object names;
        object values;

        propertySet.GetAllProperties(out names, out values);

        var nameArray = (string[])names;
        var valueArray = (object[])values;

        for (var i = 0; i < nameArray.Length; i++)
        {
            yield return new KeyValuePair<string, object>(nameArray[i], valueArray[i]);
        }
    }
}
Petr Krebs
quelle
Manchmal können Sie einfach so etwas wie ein IPropertySet mit einem speziellen Schlüssel in der ILayerExtension speichern. Da dies ein häufiger "Trick" ist, sollten Entwickler vor dem Hinzufügen eines IPropertySet prüfen, ob ein IPropertySet vorhanden ist.
James Schek
@ James: Guter Tipp, ich werde die Antwort aktualisieren.
Petr Krebs
+1 Als ich das letzte Mal überprüft habe, dass Esri nur IPersistStream - nicht IPersistVariant - für Ebenenerweiterungen berücksichtigt. Ich bin mir nicht sicher warum. Ich habe den IPersistVariant-Support um eine Verbesserung gebeten, bin mir aber nicht sicher, ob er jemals implementiert wurde. Auf jeden Fall möchten Sie vielleicht den IPersistStream-Beitrag von Richie Carmichael als Beispielcode verwenden.
Kirk Kuykendall
Was mich an der Verwendung von IPersistStream verrückt macht, ist, dass es mit Add-Ins nicht funktioniert. Das Objekt, das Sie zu den ILayerExtensions hinzufügen, muss COM CoCreatable sein.
James Schek
@ Kirk: Das stimmt, ich erinnere mich, dass ich aus diesem Grund die Persistenz der Layer-Erweiterung in VB nicht implementieren konnte. Danke für die Korrektur.
Petr Krebs