จะตรวจสอบได้อย่างไรว่ามี FeatureLayer อยู่แล้ว?


9

ขณะนี้ฉันกำลังทำงานในโครงการที่เมื่อผู้ใช้โหลดแผนที่ของพวกเขา (mxd) ลงในระบบของเราเราสร้าง featuerlayers ที่กำหนดเองหลายอย่างสำหรับพวกเขา ปัญหาของฉันคือว่าฉันไม่ทราบวิธีการตรวจสอบว่าฉันได้สร้างชั้นเหล่านั้นแล้ว (กล่าวว่าผู้ใช้โหลดขึ้น mxd, ชั้นสร้าง, บันทึก, โหลดใหม่ mxd ควรตรวจสอบว่ามีอยู่แล้วชั้น)

มี Id ที่ไม่ซ้ำสำหรับ 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 สำหรับคลาสนี้ แก้ไข: คุณสามารถใช้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 Schek

@ James: เคล็ดลับดีฉันจะอัปเดตคำตอบ
Petr Krebs

+1 ครั้งล่าสุดที่ฉันตรวจสอบ Esri เท่านั้นที่ให้เกียรติ IPersistStream ไม่ใช่ IPersistVariant สำหรับส่วนขยายเลเยอร์ ฉันไม่แน่ใจว่าทำไม ฉันได้ขอการสนับสนุน IPersistVariant เพื่อเป็นการปรับปรุง แต่ไม่แน่ใจว่าได้มีการใช้งานจริงหรือไม่ อย่างไรก็ตามคุณอาจต้องการใช้การโพสต์ IPersistStreamของ Richie Carmichael สำหรับโค้ดตัวอย่าง
Kirk Kuykendall

สิ่งที่ทำให้ฉันคลั่งไคล้ในการใช้ IPersistStream ก็คือมันไม่ทำงานกับ Add-In วัตถุที่คุณเพิ่มลงใน ILayerExtensions ต้องเป็น COM CoCreatable
James Schek

@ เคิร์ก: ถูกต้องฉันจำไม่ได้ว่าจะไม่สามารถใช้การคงอยู่ของส่วนขยายเลเยอร์ใน VB ได้ ขอบคุณสำหรับการแก้ไข
Petr Krebs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.