// <summary>
        // Gets all relevant sub-properties from the value of the specified
        // ModelProperty
        // </summary>
        // <param name="property">ModelProperty to examine</param>
        // <returns>Sub-properties exposed by the value of the specified ModelProperty</returns>
        public static List <ModelProperty> GetSubProperties(ModelProperty property)
        {
            if (property.Value == null || ModelUtilities.GetSafeRawValue(property) == null)
            {
                return(null);
            }

            // First, see if there is a custom TypeConverter.  If so, get the subProperties
            // from there.  Otherwise, get all subProperties including those that aren't browsable,
            // since the Browsability call should be made by the UI, not by the model.
            return(GetTypeConverterSubProperties(property) ?? GetAllSubProperties(property));
        }
        // <summary>
        // Computes the IsReadOnly flag for the specified set of properties, ORing
        // results together for sets of properties larger than 1.
        // </summary>
        // <param name="properties">Properties to examine</param>
        // <param name="isMixedValueDelegate">Delegate that evaluates the IsMixedValue flag for
        // the passed in property values (added as an optimization, since we don't always require
        // the value and it may be computationally expensive)</param>
        // <returns>Flag indicating whether the set of properties is read only or not</returns>
        public static bool IsReadOnly(List <ModelProperty> properties, IsMixedValueEvaluator isMixedValueEvaluator)
        {
            if (properties == null || properties.Count == 0)
            {
                Debug.Fail("ExtensibilityAccessor.IsReadOnly: No properties specified.");
                return(true);
            }

            Type propertyType = properties[0].PropertyType;

            // ILists are readonly only if value is null
            if (typeof(IList).IsAssignableFrom(propertyType))
            {
                if (OrReadOnlyValues(properties))
                {
                    IList list = null;
                    if (isMixedValueEvaluator != null)
                    {
                        list = isMixedValueEvaluator() ? null : (ModelUtilities.GetSafeRawValue(properties[0]) as IList);
                    }
                    else
                    {
                        Debug.Fail("No delegate to evaluate IsMixedValue specified.");
                    }

                    if (list == null)
                    {
                        return(true);
                    }
                }

                return(false);
            }

            // Arrays and ICollections are readonly
            if (typeof(Array).IsAssignableFrom(propertyType) || typeof(ICollection).IsAssignableFrom(propertyType))
            {
                return(true);
            }

            // Types that implement ONLY ICollection<> or ONLY IList<> (meaning they
            // don't also implement ICollection or IList, which we handle above)
            // are also readonly
            if (ModelUtilities.ImplementsICollection(propertyType) || ModelUtilities.ImplementsIList(propertyType))
            {
                return(true);
            }

            // Otherwise, go off of the IsReadOnly value in ModelProperty
            return(OrReadOnlyValues(properties));
        }