Working with Dependent Picklists

The following code can be used as a basis for a utility class that returns the metadata for a controller and dependent picklist:

public class DependentField
{

    /// <summary>
    /// Dictionary of Lists of strings containing dependent values with the keys of the controlling field values
    /// </summary>
    /// <param name="sObject">API name of the SObject</param>
    /// <param name="controllingFieldName">API name of the controlling picklist</param>
    /// <param name="dependentFieldName">API name of the dependent picklist</param>
    public static Dictionary<string, List<string>> GetControllingAndDependentPicklistValues(string sObject, string controllingFieldName, string dependentFieldName)
    {
        Dictionary<string, List<string>> dependencies = new Dictionary<string, List<string>>();

        SalesforceSession salesforceSession = SessionTest.GetActiveSession();

        DescribeSObjectResult describeSObjectResult = salesforceSession.Binding.describeSObjectCached(sObject);

        Field controllingField = describeSObjectResult.fields.ToList().Single(f => f.name == controllingFieldName);
        Field dependentField = describeSObjectResult.fields.ToList().Single(f => f.name == dependentFieldName);

        //confirm everything is set up properly
        Debug.Assert(controllingField.type == fieldType.picklist, "Controlling field needs to be a picklist");
        Debug.Assert(dependentField.type == fieldType.picklist, "Dependent field needs to be a picklist");
        Debug.Assert(dependentField.dependentPicklist, "Dependent field needs to be a dependent picklist");
        Debug.Assert(dependentField.controllerName == controllingFieldName, "Dependent field controlling field name needs to be " + controllingFieldName);

        for (int i = 0; i < dependentField.picklistValues.Length; i++)
        {
            Bitset validFor = new Bitset(dependentField.picklistValues[i].validFor);

            for (int k = 0; k < validFor.size(); k++)
            {
                if (validFor.testBit(k))
                {
                    string value = controllingField.picklistValues[k].label;

                    List<string> values;

                    if (dependencies.TryGetValue(value, out values))
                    {
                        if (!values.Contains(value))
                        {
                            values.Add(dependentField.picklistValues[i].value);
                        }
                    }
                    else
                    {
                        values = new List<string>();
                        values.Add(dependentField.picklistValues[i].value);

                        dependencies.Add(value, values);
                    }
                }
            }

        }

        return dependencies;
    }

    /// <summary>
    /// Inner class to decode a "validFor" bitset
    /// </summary>
    class Bitset
    {

        byte[] data;

        public Bitset(byte[] data)
        {
            this.data = data == null ? new byte[0] : data;
        }

        public bool testBit(int n)
        {
            return (data[n >> 3] & (0x80 >> n % 8)) != 0;
        }

        public int size()
        {
            return data.Length * 8;
        }

    }

}

Usage

In the following example, the controlling picklist Beverage has two values, which relate to the values of the dependent picklist Beverage Variety on the Product2 SObject:

BeverageBeverage Variety
CoffeeDecaffeinated

Regular
TeaChamomile

Earl Grey

English Breakfast

To get the Dictionary of controlling and dependent field values, execute the following code for the class above:

  Dictionary<string, List<string>> dependentPicklistValues = DependantField.GetControllingAndDependentPicklistValues(Product2.SFType, "Beverage__c", "Beverage_Variety__c");

This will return a dictionary with the string keys "Coffee" and "Tea" along with string Lists containing their respective dependent values.

More information can be found here: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_describesobjects_describesobjectresult.htm#about_dep_picklist