Select to view content in your preferred language

Find correct layer in map

3055
16
12-02-2010 12:02 PM
HenkZwols
Regular Contributor
Hello,

In a combobox i store all the names of layers that are in the TOC:
water
buildings
buildings
...
As you can see there are 2 layers with the same name, but different definition queries: buildings.
When user selects a layer in the combobox i perform an action on that layer. My routine 'selectLayerByName' fails when user selects the second building layer.

What code do i need to find the correct layer?
[Edit] Or what extra information do i need to store in de combobox to find the correct layer?

Gr. Henk
0 Kudos
16 Replies
HenkZwols
Regular Contributor
Why don't you make names as by type Commercial building and residential or by size Large Constructions and Small Constructions  something like that ?


I know, but it is up to the user of my tool what names he uses. My tool must be able to handle layers with equal names.
0 Kudos
LeoDonahue
Deactivated User
This is an ESRI sample method for finding a layer in a map.  The sample is Java based:

Using the sample below, when you have two layers with the same name in a map, will the second layer with the same name ever get selected?  No.

You need a way to distinguish between the two layers with the same name, when you are creating your layer.  The only way to to do this would be to organize your map with the layers in a defined order (and not change the order), and use the index of the layer in the map.  Then you can add the same layer name to your combo box and use the index associated with the two layers that have the same name.

Luckily for you, you can get the map layer by ID, without using a loop.
http://resources.esri.com/help/9.3/arcgisserver/adf/java/help/api/arcobjects/com/esri/arcgis/carto/M...


    public FeatureLayer getLayerByName(String layerName, com.esri.arcgis.carto.Map map) {
        FeatureLayer layer = null;
        try {
            for (int i = 0; i < map.getLayerCount(); i++) {
                if (map.getLayer(i).getName().equalsIgnoreCase(layerName)) {
                    layer = (FeatureLayer) map.getLayer(i);
                    break;
                }
            }
        } catch (AutomationException ae) {
            ae.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return layer;
    }
0 Kudos
Venkata_RaoTammineni
Regular Contributor
I know, but it is up to the user of my tool what names he uses. My tool must be able to handle layers with equal names.


See...handling same layers name is not an issue...only thing is how user can feel good to use...what he suppose to select if he wants to see the building or something...why he suppose to check all building layers ?
0 Kudos
JamesCrandall
MVP Alum
Here's an idea to make certain layer names in the TOC are unique and correspond to the items found in your ComboBox.  Honestly, I don't see a "good" scenario where I would allow the user to have duplicate layer names loaded, even though they are the same Dataset.Name from the datasource.

If this isn't a good solution, perhaps you could utilize some of it to fit your needs.


This could be added to the Load event of the Form:

       
Dim theListOfLayers As List(Of String) = GetLayerList()

        pDoc = m_pApp.Document
        pMap = pDoc.FocusMap

        For l = 0 To pMap.LayerCount - 1
            For x = 0 To theListOfLayers.Count - 1
                Dim indxOrig As Integer = theListOfLayers.IndexOf(theListOfLayers(x).Trim)
                Dim indx As Integer = theListOfLayers.LastIndexOf(theListOfLayers(x).Trim)
                If indxOrig <> indx Then
                    pMap.Layer(l).Name = theListOfLayers(x).Trim & "2"
                    theListOfLayers(x) = theListOfLayers(x).Trim & "2"
                End If
            Next
            Exit For
        Next

        'update the TOC
        pDoc.UpdateContents()

        'add the list of layernames to the ComboBox
        cboLayerList.DataSource = theListOfLayers


Add this private function to the form to build the List(Of String) of Layer names loaded in the TOC:

   
Private Function GetLayerList() As List(Of String)
        Dim LayerList As New List(Of String)

        Dim pDoc As ESRI.ArcGIS.ArcMapUI.IMxDocument
        Dim pMap As ESRI.ArcGIS.Carto.IMap

        pDoc = m_pApp.Document
        pMap = pDoc.FocusMap

        For i = 0 To pMap.LayerCount - 1
            LayerList.Add(pMap.Layer(i).Name)
        Next

        Return LayerList

    End Function
0 Kudos
HenkZwols
Regular Contributor
See...handling same layers name is not an issue...only thing is how user can feel good to use...what he suppose to select if he wants to see the building or something...why he suppose to check all building layers ?


It's a very smart user 😉 . He adds two layers with the same name en applies two different definition queries. For the moment its easy to remember which layers and what queries he added while testing his code. When he selects a layer in de combobox the form shows the definition queries he applied and so he knows what layer to select. He selects the second layer and hits the commandbutton to perform an action on that layer. Now he is wondering why the tool is processing the wrong features. It takes 10 seconds to find out what the problem is: the code is using only the name of the layer and finds the first layer.
So he thinks of a solution. There must be a another way to identify a layer, but he can't figure it out and goes to this forum to find an answer to his problem.

He decides to change the code so that it's checking for duplicate names in the TOC and renames them without asking:

Sub getlayers()
    Dim pMxDocument As IMxDocument
    Dim pMap As IMap
    Set pMxDocument = ThisDocument
    Set pMap = pMxDocument.FocusMap
    Dim Player As ILayer
    Dim pEnumLayers As IEnumLayer
    Dim pFeatureLayer As IFeatureLayer
    
    Dim pId As New UID
    pId = "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}"         'Find only IGeoFeatureLayers
    Set pEnumLayers = pMap.Layers(pId, True)

    If pEnumLayers Is Nothing Then Exit Sub

    Dim newName As String
    Randomize
    Set Player = pEnumLayers.Next
    Do While Not Player Is Nothing
        If Player.Valid Then
            Set pFeatureLayer = Player

            If nameInList(ComboBoxLayers, pFeatureLayer.name) Then
                newName = pFeatureLayer.name & Int(Rnd * 100)
                MsgBox "Layer " & pFeatureLayer.name & " renamed to " & newName, vbInformation
                pFeatureLayer.name = newName
                pMxDocument.CurrentContentsView.Refresh 1
            End If

            ComboBoxLayers.AddItem pFeatureLayer.name
        End If
    Set Player = pEnumLayers.Next
    Loop
End Sub

Function nameInList(ComboBoxIn As ComboBox, name As String) As Boolean
    Dim i As Long
    For i = 0 To ComboBoxInlistCount - 1
        If ComboBoxIn.List(i) = name Then nameInList = True
    Next i
End Function


Now everybody is happy because there are no duplicate names anymore.


Thank you all.

Henk

(Still thinking about implementing Alexander Gray's solution of using a generic list of IFeatureLayers)
0 Kudos
ThavitinaiduGulivindala
Regular Contributor
Hi,
I also had come across the situation and below is the solution I found. This displays a unique reference in combobox for a layer in the map. Hence if there is a layer with duplicate name in map then combobox will have duplicate names but each refers to unique layer in map.

Create a custom class for Feature Layer and return layer name on �??ToStrong()�?? method. Add the custom feature layer object to combox as shown below.
FeatureLayerDropDownItem FLayerDropDownObj = new FeatureLayerDropDownItem((IFeatureLayer)layer);
cmbBox.Items.Add(FLayerDropDownObj);

Below is the code for creating custom class.


///<summary>
/// Custom Class the refers to a Feature Layer. This object has overridden method 'ToString' methods that returns FeatureLayer's Name.
/// This cutom object is used to load the Layers into the Combobox control
///</summary>
public class FeatureLayerDropDownItem
{
///<summary>
/// Feature Layer that this object refer to
///</summary>
IFeatureLayer m_FeatureLayer;

///<summary>
/// Constructor
///</summary>
///<param name="featureLayer">Feature Layer that this object refers to</param>
public FeatureLayerDropDownItem(IFeatureLayer featureLayer)
{
m_FeatureLayer = featureLayer;
}

///<summary>
/// Name of the Feature Layer
///</summary>
///<returns></returns>
public override string ToString()
{
if (m_FeatureLayer == null) return "";
//return the name of the feature layer as the ToString value that will be displayed in the drop down list
return m_FeatureLayer.Name;
}

///<summary>
/// Checks the equality of the current and passed object.
/// The equality condition is true if their associtaed FeatureLayer objects are same and false otheriwse.
///</summary>
///<param name="obj">Object to check the equality</param>
///<returns>The equality condition is true if their associtaed FeatureLayer objects are same and false otheriwse.</returns>
public override bool Equals(object obj)
{
try
{
//if both are null, then return true
if (m_FeatureLayer == null && obj == null) return true;
//return false, if any one is null
else if (m_FeatureLayer == null || obj == null) return false;
//checks if the passed object type is same as that of this object
if (!(obj is FeatureLayerDropDownItem)) return false;
//checks whether FeatureLayer of both the objects are equal. If yes, then declare that both the objects are equal.
if (((FeatureLayerDropDownItem)obj).FeatureLayerAssociated == m_FeatureLayer) return true;
else return false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}

///<summary>
/// Feature Layer that this object refer to
///</summary>
public IFeatureLayer FeatureLayerAssociated
{
get
{
return m_FeatureLayer;
}
set
{
m_FeatureLayer = value;
}
}

///<summary>
/// Geometry Type of the Features that this Feature Layer stores
///</summary>
public esriGeometryType LayerGeometryType
{
get
{
//return esriGeometryNull if the Associtaed FeatureLayer or its associated FeatureClass is null.
if (m_FeatureLayer == null || m_FeatureLayer.FeatureClass == null) return esriGeometryType.esriGeometryNull;
else return m_FeatureLayer.FeatureClass.ShapeType;
}
}

}
0 Kudos
HenkZwols
Regular Contributor

How are you adding layer names to the ComboBox? are you using recursion to find any nested layers inside a group layer? Or simply looping through the layers in the table of contents?

See my code i posted.


What exactly are you doing with the layer that the user selects?

User selects a layer and hits a startbutton:
- Write all the features from selected layer that match the definition query to a scratch database.
- Add a topologyclass with some rules.
- Validate the topology.
- Create 3 new featureclasses containing the geometries of the topology errors.
- Add the new featureclasses to the map.

Why? Because we are working an a SDE Oracle database that omits some topology rules. We can't change that in a short time because of the changemanagementsystem.

Henk
0 Kudos