I'm working on an ESRI-Addin written in vb.net. I have a FeatureClass with subtypes (POI with categories). Each subtype (category) has a coded value domain defining the subcategories.

I managed to populate one combobox with the categories. See code below:

    Public Class frmFind
        Private Sub frmFind_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        End Sub

    Private Sub PopulateCategory()
            Dim pFeatureClass As IFeatureClass = GetFeatureClass()
            Dim pSubtypes As ISubtypes = pFeatureClass
            Dim eSubtypes As IEnumSubtype = pSubtypes.Subtypes

            Dim rCode As Integer
            Dim rName As String
            Dim dicCategories As New Dictionary(Of Integer, String)
            rName = eSubtypes.Next(rCode)
            Do While rName <> ""
                dicCategories.Add(rCode, rName)
                rName = eSubtypes.Next(rCode)

            cmbCategory.DataSource = New Windows.Forms.BindingSource(dicCategories, Nothing)
            cmbCategory.DisplayMember = "Value"
            cmbCategory.ValueMember = "Key"
        End Sub
    End Class

Now I want to populate the second combobox with the subcategories based on the selection in the first combobox. So this is what I got so far:

    Public Class frmFind
        Private Sub frmFind_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        End Sub

    Private Sub cmbCategory_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbCategory.SelectedIndexChanged
        Dim pKeyValuePair As KeyValuePair(Of Integer, String) = cmbCategory.SelectedItem
    End Sub


    Private Sub PopulateSubcategory(categorycode As Integer)
        Dim pFeatureClass As IFeatureClass = GetFeatureClass()

        Dim pQFilter As IQueryFilter2 = New QueryFilter
        pQFilter.WhereClause = "KAT_ID = " & categorycode

        Dim pFeatureCursor As IFeatureCursor = pFeatureClass.Search(pQFilter, False)

        Dim pFeature As IFeature = pFeatureCursor.NextFeature

        ' Here should be a loop

        cmbSubcategory.DataSource = New Windows.Forms.BindingSource(dictSubcategory, Nothing)
        cmbSubcategory.DisplayMember = "Value"
        cmbSubcategory.ValueMember = "Key"

    End Sub

I'm struggling to get only the domains and not all features of that category. Could anybody familiar with ArcObjects give me hint?


First when you're saying categories you're talking about two different things (unless I am misunderstanding). First you have the subtype. Second you have a domain. For the purposes of this explanation I'm going to make a couple assumptions.

  1. You only have a coded value domain (basically a dictionary) of associated values.
  2. The domains are defined by subtype (potentially they could come from the field object itself)

Here's the code to get to the domain's values:

//get a subtype value, what you are storing as the Key, pretty sure this is always 
int selected_subtype = my_selected_subtype;

//decide what field you are looking for subcategories withing
string field = "ABC";

//next you'll need access to the associated feature class to get the subtypes
ISubtypes subtypes = my_feature_class as ISubtypes;

//now find the associated domain for the field, in this case an ICodedValueDomain
object domain = subtypes.Domain[selected_subtype, field];

//the field may not have a domain
if(domain != null)
    ICodedValueDomain code_domain = domain as ICodedValueDomain;
    //the ICodedValueDomain works similarly to the Subtype, it's essentially a glorified dictionary 
    //you can now loop through the domain's values like so
    for (int i = 0; i < cvd.CodeCount; i++)
        object value_code = cvd.Value[i];
        string value_name = return cvd.Name[i];
| improve this answer | |
  • Thank you very much. Although I'm not familiar with C# (and actually object oriented programming in general), I've managed to adapt your code somehow. Now I'm just wondering: If ICodedValueDomain already is a “glorified dictionary”, how can I fill it and use it for the cmbSubcategory.DataSource like I've done it with the dicCategories? Because I want the DisplayMember to be the name but the actual ValueMember to be the code. – maaattes Jun 18 at 11:39
  • 2
    There is documentation for the ICodedValueDomain here: resources.arcgis.com/en/help/arcobjects-net/componenthelp/… You can't link this object to the combo box, so you'd need to fill that by binding to a .NET Dictionary or manually adding values to the combo box. – danielm Jun 18 at 16:13

I have some (very) old code for working with subtypes and coded value domains which might be helpful; it is a very cut down section of code that was used for populating comboboxes on a form to be used instead of the attribute editor (limiting fields, appearing at the cursor) so the flow may not be entirely logical though I assure you there are some insights on how subtypes, default values and domains interrelate inside a geodatabase feature class.. not to detract from danielms' answer but to include iteration and the code is VB.net, same as the sample code in your question.

Dim pSubShow As String
Dim pSubCode As Long
Dim pDomain As IDomain

Dim pSubType As ISubtypes = pEdLay(pLayListIndex).FeatureClass 'pEdLay is of type IEditLayers'
Dim pFields As IFields = pEdLay(pLayListIndex).FeatureClass.Fields 'pLayListIndex is type long, the index of the layer in the list of layers'
Dim pHasSub As Boolean = pSubType.HasSubtype ' an option exists here if there are no subtypes defined'
Dim pDefaultSub As Long = pSubType.DefaultSubtypeCode
Dim pEnumSubType As IEnumSubtype = pSubType.Subtypes

If pHasSub Then
    ' Loop through the defined subtypes pSubShow is the text description for the pSubCode numeric value'
    pSubShow = pEnumSubType.Next(pSubCode)
    Do While Len(pSubShow) > 0
    pSubShow = pEnumSubType.Next(pSubCode)

    ' Access the values for default value for a given field in a subtype'
    ' and, if specified, the valid fields in the coded domain'
    For pFcnt = 0 To pFields.FieldCount - 1
    pDomain = pSubType.Domain(pPickedListIndex, pFields.Field(pFcnt).Name)
    If pDomain Is Nothing Then
        ' only a default value (if set), no picklist of values'
        ' note pPickedListIndex As Long is passed to the function'
        pDefaultValue = pSubType.DefaultValue(pPickedListIndex, pFields.Field(pFcnt).Name)
        pList = False
        pDefaultValue = pSubType.DefaultValue(pPickedListIndex, pFields.Field(pFcnt).Name)
        If TypeOf pDomain Is ICodedValueDomain Then
        pList = True
        pCVdomain = pDomain
        For pAddedValIndex = 0 To pCVdomain.CodeCount - 1
            pComBox.Items.Add(pCVdomain.Value(pAddedValIndex) & ":" & pCVdomain.Name(pAddedValIndex))
        Next pAddedValIndex
        End If
    End If

    Next pFcnt
End If

This code is lazy, I never used ctype() in VB.net (or VB6 or VBA) because it worked just fine without the implicit conversion which is ultra important in C# (and C++). Please let me know if I've forgotten to Dim a variable, like I said this is very cut down and the initial Dim may not have been included.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.