Як перевірити, чи існує вже FeatureLayer?


9

Зараз я працюю над проектом, коли користувач завантажує свою карту (mxd) в нашу систему, ми створюємо для них кілька спеціальних ігрових програм. Моя проблема, однак, я не маю уявлення, як перевірити, чи я вже створив ці шари (скажімо, користувач завантажує mxd, створені шари, зберегти, перезавантажити mxd, слід перевірити, чи вже існують шари).

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

Я створив свій шар як об'єкт бізнес-класів, що характеризується таким класом.

Код:

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

Дякую і з повагою, Кевін

Відповіді:


7

Класи функцій та об’єктні класи мають свої ідентифікатори, унікальні в межах однієї бази даних. Це дуже часто задовольняє більшість сценаріїв, аналогічних вашому.

Якщо ви не можете однозначно ідентифікувати шар на основі класу його функцій, ви можете використовувати розширення шару для зберігання довільних даних із шаром.

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

Тож ваше завдання полягало б у наступному:

  • Створіть COM-клас, який би зберігав ваш прапор (або якийсь згенерований ідентифікатор). Реалізуйте IPersistStream для цього класу. EDIT: ви можете легко використовувати PropertySet як об’єкт розширення шару, а не створювати власний клас.
  • Коли ви додаєте шар, перегляньте всі шари на карті та перевірте, чи присвоєно якомусь із них розширення шару із збереженими вашими даними.
  • Якщо це так, не додайте шар, як він уже є.
  • Якщо ні, додайте шар та додайте до нього екземпляр розширення шару за допомогою ILayerExtensions.

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

EDIT: нижче я розміщую код для статичного класу помічника, який дозволяє швидко працювати з властивостями, встановленими всередині набору властивостей, що зберігається в розширенні шару (необхідний .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 IPersistStream для зразкового коду.
Кірк Куйкендалл

Те, що зводить мене з розуму від використання IPersistStream, - це те, що воно не працює з додатками. Об'єкт, який ви додаєте до ILayerExtensions, повинен бути COM CoCreatable.
Джеймс Шек

@Kirk: це правильно, я пам’ятаю, що не міг реалізувати стійкість розширення шару в VB завдяки цьому. Дякуємо за виправлення.
Петро Кребс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.