FeatureLayerがすでに存在するかどうかを確認する方法は?


9

私は現在、ユーザーがマップ(mxd)をシステムにロードするときに、いくつかのカスタムfeatuerlayersを作成するプロジェクトに取り組んでいます。しかし、私の問題は、それらのレイヤーがすでに作成されているかどうかを確認する方法がわからないことです(たとえば、ユーザーがmxdをロードし、レイヤーを作成して保存し、mxdを再ロードすると、レイヤーがすでに存在するかどうかを確認する必要があります)。

ArcEngine10のFeatuerLayerClassに一意のIDがありますか?FeatureLayerClass.FeatureClassにOIDNameとObjectClassIDがありますが、それらは機能していないようです(ObjectClassIdを割り当てることができず、OIDNameにUniqueIdを使用したい)。

このように、layerを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;
            }

おかげで、よろしく、ケビン

回答:


7

フィーチャクラスとオブジェクトクラスにはIDがあり、単一のジオデータベース内で一意です。これは多くの場合、あなたのシナリオに似たほとんどのシナリオを満たします。

フィーチャクラスに基づいてレイヤーを一意に識別できない場合は、レイヤー拡張を利用して、レイヤーに任意のデータを保存できます。

レイヤー拡張は、ILayerExtensionsインターフェイスを介してレイヤーに追加できます。現在、レイヤー拡張に共通のインターフェイスはありませんが、通常、IPersistStreamを介して永続性を実装しています。レイヤー拡張は特別なことは何もしませんが、追加したレイヤーを一意に識別するデータを格納します。

したがって、あなたの仕事は次のようになります:

  • フラグ(または生成されたIDの一種)を格納する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]);
        }
    }
}

場合によっては、ILayerExtensionに特別なキーを持つIPropertySetのようなものを格納するだけで済むことがあります。これは一般的な「トリック」であるため、追加する前に、IPropertySetの存在を確認する必要があります。
James Schek、2011年

@ジェームズ:良いヒント、答えを更新します。
Petr Krebs

Esriを前回チェックしたときの+1は、レイヤー拡張に対してIPersistVariantではなくIPersistStreamのみを尊重します。理由はわかりません。拡張機能としてIPersistVariantのサポートを依頼しましたが、これが実装されたかどうかはわかりません。とにかく、サンプルコードにはRichie CarmichaelのIPersistStream投稿を使用することをお勧めします。
Kirk Kuykendall

IPersistStreamの使用に夢中になるのは、アドインでは機能しないことです。ILayerExtensionsに追加するオブジェクトは、COM CoCreatableでなければなりません。
James Schek

@カーク:そうです、そのためにVBでレイヤー拡張の永続性を実装できないことを覚えています。訂正ありがとうございます。
Petr Krebs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.