Как проверить, если FeatureLayer уже существует?

9

В настоящее время я работаю над проектом, в котором, когда пользователь загружает свою карту (mxd) в нашу систему, мы создаем для него несколько пользовательских слоев персонажа. Моя проблема, однако, я не знаю, как проверить, если я уже создал эти слои уже (скажем, пользователь загружает MXD, слои созданы, сохранить, перезагрузить MXD, должен проверить, если слои уже существуют).

Существует ли уникальный идентификатор для FeatuerLayerClass в ArcEngine10, есть OIDName и ObjectClassID в FeatureLayerClass.FeatureClass, но они, похоже, не работают (не могут назначить ObjectClassId и хотят использовать UniqueId для OIDName)?

Я создал свой слой как бизнес-объект featurelayerclass, как этот.

Код:

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

Создание рабочего пространства

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

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

        }

Код для получения слоя

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

Спасибо и всего наилучшего, Кевин

Kev84
источник

Ответы:

7

Классы объектов и классы объектов имеют свои идентификаторы, которые являются уникальными в одной базе геоданных. Это очень часто удовлетворяет большинству сценариев, подобных вашему.

Если вы не можете однозначно идентифицировать слой на основе его класса пространственных объектов, вы можете использовать расширения слоя для хранения произвольных данных со слоем.

Расширение слоя может быть добавлено к слою через интерфейс ILayerExtensions . Теперь нет общего интерфейса для расширений уровня, но они обычно реализуют некоторую устойчивость через IPersistStream . Ваше расширение слоя не будет делать ничего особенного, но будет хранить некоторые данные, по которым вы будете уникально идентифицировать добавленный слой.

Таким образом, ваша задача будет выглядеть следующим образом:

  • Создайте COM-класс, в котором будет храниться ваш флаг (или какой-то сгенерированный идентификатор). Реализуйте IPersistStream для этого класса. РЕДАКТИРОВАТЬ: вы можете легко использовать PropertySet в качестве объекта расширения слоя, вместо создания своего собственного класса.
  • Когда вы добавляете слой, просматривайте все слои на карте и проверяете, есть ли у каждого из них назначенное расширение слоя с сохраненными данными, которые вы ожидаете.
  • Если это так, не добавляйте слой, поскольку он уже присутствует.
  • Если нет, добавьте слой и добавьте в него экземпляр вашего расширения слоя через ILayerExtensions.

У меня была очень похожая проблема, и расширения слоев оказались наиболее подходящими.

РЕДАКТИРОВАТЬ: ниже я публикую некоторый код для вспомогательного статического класса, который позволяет вам быстро работать со свойствами, установленными внутри набора свойств, хранящегося в расширении слоя (требуется .NET 3.5 или выше). Он заботится о доступе к объекту расширения и его создании, если он еще не назначен слою. Используется так:

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

Вместо «SomeValue» вы, вероятно, создадите и сохраните там какой-то идентификатор слоя.

Вот полный исходный код для PropertySetLayerExtensionHelperкласса:

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]);
        }
    }
}
Петр Кребс
источник
Иногда вы можете просто сохранить что-то вроде IPropertySet с помощью специального ключа в ILayerExtension. Поскольку это обычная «хитрость», разработчики должны проверить наличие IPropertySet перед добавлением.
Джеймс Шек,
@James: хороший совет, я обновлю ответ.
Петр Кребс
+1 В прошлый раз я проверял Esri только для IPersistStream - не IPersistVariant - для расширений слоя. Я не уверен почему. Я попросил поддержку IPersistVariant как улучшение, но не уверен, что он когда-либо был реализован. В любом случае, вы можете захотеть использовать публикацию Richers Carmichael's IPersistStream для примера кода.
Кирк Кайкендалл
То, что сводит меня с ума от использования IPersistStream, это то, что он не работает с надстройками. Объект, который вы добавляете в ILayerExtensions, должен быть COM CoCreatable.
Джеймс Шек
@Kirk: верно, я помню, что не смог реализовать постоянство расширения слоя в VB из-за этого. Спасибо за исправление.
Петр Кребс