I am trying to loop through layers in a map and return the name of the feature dataset. I will then be performing some task on features in a specific feature dataset. My map however is complex and includes some layers that do not reside in a feature dataset. My code errors at this point. I would like to somehow step over these layers without error. The line If pFeatureLayer.DataSourceType = "SDE Feature Class" is an attempt to limit my results since all of those layers reside in a feature dataset but that doesn't seem to be working. I am new to ArcObject so any help would be greatly appreciated!
Here is my code:
Dim pMapDocument As IMapDocument = New MapDocument() If pMapDocument.IsMapDocument(destfile) Then pMapDocument.Open(destfile, Nothing) Dim pMap As IMap Dim i As Integer For i = 0 To pMapDocument.MapCount - 1 Step 1 + 1 pMap = pMapDocument.Map(i) MsgBox(pMapDocument.DocumentFilename) Dim pEnumLayer As IEnumLayer Dim pID As New UID Dim pFeatureClass As IFeatureClass Dim pDataset As IDataset Dim pFeatureLayer As IFeatureLayer2 pID.Value = "{6CA416B1-E160-11D2-9F4E-00C04F6BC78E}" pEnumLayer = pMap.Layers(pID, True) pEnumLayer.Reset() pFeatureLayer = CType(pEnumLayer.Next, IFeatureLayer2) Do Until pFeatureLayer Is Nothing If pFeatureLayer.DataSourceType = "SDE Feature Class" Then pFeatureClass = pFeatureLayer.FeatureClass pDataset = pFeatureClass.FeatureDataset MsgBox(pDataset.Name) End If pFeatureLayer = CType(pEnumLayer.Next, IFeatureLayer2) Loop Next i End If Next
You should be able to check if cast the layer to IFeatureLayer and then check if the FeatureLayer.FeatureClass.FeatureDataset is equal to null. If it is null then the dataset is not within a feature dataset.
I would assume that your code would fail on the call the pDataset.Name when the dataset is not within a feature dataset because the call to pFeatureClass.FeatureDataset will be null. Below is the code I used to confirm along with a sample that will display this for you.
using System.Collections.Generic; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.esriSystem; using System; using System.IO; using System.Reflection; namespace ListFeatureDatasets class Program { private static readonly LicenseInitializer m_aoInit = new LicenseInitializer(); private static readonly String m_srcPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); private static readonly String m_mxdPath = Path.Combine(m_srcPath, @"data\SanDiego.mxd"); [STAThread()] static void Main(string[] args) { //ESRI License Initializer generated code. m_aoInit.InitializeApplication(new [] { esriLicenseProductCode.esriLicenseProductCodeAdvanced }, new esriLicenseExtensionCode[] { }); var mxd = new MapDocumentClass(); mxd.Open(m_mxdPath); Dictionary<string, List<string>> results = new Dictionary<string, List<string>>(); for (int i = 0; i < mxd.MapCount; i++) { var map = mxd.Map; var uid = new UIDClass {Value = "{40A9E885-5533-11D0-98BE-00805F7CED21}"}; // IFeatureLayer var enumLayer = map.Layers[uid, true]; enumLayer.Reset(); ILayer layer; while ( (layer = enumLayer.Next()) != null) { var fc = (layer as IFeatureLayer).FeatureClass; if (fc.FeatureDataset != null) { if (results.ContainsKey(fc.FeatureDataset.Name)) results[fc.FeatureDataset.Name].Add(fc.AliasName); else results[fc.FeatureDataset.Name] = new List<string> {fc.AliasName}; } else Console.WriteLine("Skipping {0}...NOT within a Feature Dataset", fc.AliasName); } } foreach (var kvp in results) Console.WriteLine("FEATURE DATASET: {0}\n...{1}\n", kvp.Key, String.Join("\n...", kvp.Value)); Console.WriteLine(); Console.Write("Press enter to exit..."); Console.ReadLine(); //ESRI License Initializer generated code. //Do not make any call to ArcObjects after ShutDownApplication() m_aoInit.ShutdownApplication(); } } }
Thank you Freddie. This is very helpful. Could you let me know what results.ContainsKey is doing and what the equivalent is in VB.NET. I am new to ArcObject and so far have not been using c#.
That portion of the code is about using Dictionaries. You can read up on this concept on the following page:
C# Dictionary
http://www.dotnetperls.com/dictionary
This is a data structure in .NET that is not related to ArcObjects. Think of it like an actual dictionary. In a dictionary a word (i.e. key) will be defined once and the definition (i.e. value) will consist of multiple words, which can be repeated. I used the name of the feature dataset as the key in the dictionary and used the names of the feature classes as the values so that I easily organize which feature classes were in which feature dataset and print out a "prettier" list of the results. If you want you could simplify this logic as follows:
ILayer layer; // while ( (layer = enumLayer.Next()) != null) // { // var fc = (layer as IFeatureLayer).FeatureClass; // if (fc.FeatureDataset != null) // { // if (results.ContainsKey(fc.FeatureDataset.Name)) // results[fc.FeatureDataset.Name].Add(fc.AliasName); // else // results[fc.FeatureDataset.Name] = new List<string> {fc.AliasName}; // } // else // Console.WriteLine("Skipping {0}...NOT within a Feature Dataset", fc.AliasName); // } //} //foreach (var kvp in results) // Console.WriteLine("FEATURE DATASET: {0}\n...{1}\n", kvp.Key, String.Join("\n...", kvp.Value)); while ((layer = enumLayer.Next()) != null) { var fc = (layer as IFeatureLayer).FeatureClass; if (fc.FeatureDataset != null) Console.WriteLine("FEATURE CLASS: {0,-20} | FEATURE DATASET: {1}", fc.AliasName, fc.FeatureDataset.Name); }
Below are screenshots of the results of these two options.
** Option A : using dictionary **
** Option B **