/// <summary> /// Creates the property item list. /// </summary> /// <param name="instance"> /// The instance. /// </param> /// <param name="isEnumerable"> /// if set to <c>true</c> [is enumerable]. /// </param> /// <returns> /// A list of <see cref="PropertyItem"/>. /// </returns> public virtual IList <PropertyItem> CreateItems(object instance, bool isEnumerable) { if (instance == null) { return(null); } var instanceType = instance.GetType(); var properties = TypeDescriptor.GetProperties(instance); this.PropertyItemFactory.Reset(); var items = new List <PropertyItem>(); foreach (PropertyDescriptor pd in properties) { if (this.ShowDeclaredOnly && pd.ComponentType != instanceType) { continue; } // Skip properties marked with [Browsable(false)] if (!pd.IsBrowsable) { continue; } // Read-only properties if (!this.ShowReadOnlyProperties && pd.IsReadOnly) { continue; } // If RequiredAttribute is set, skip properties that don't have the given attribute if (this.RequiredAttribute != null && !AttributeHelper.ContainsAttributeOfType(pd.Attributes, this.RequiredAttribute)) { continue; } var pi = this.PropertyItemFactory.CreatePropertyItem(pd, instance); items.Add(pi); } return(items.OrderBy(t => t.SortIndex).ToList()); }
/// <summary> /// This method takes an object Instance and creates the property model. /// The properties are organized in a hierarchy /// PropertyTab /// PropertyCategory /// Property|OptionalProperty|WideProperty|CheckBoxProperty /// </summary> /// <param name = "instance"> /// </param> /// <param name = "isEnumerable"> /// </param> /// <returns> /// Collection of tab ViewModels /// </returns> public virtual IList <TabViewModel> CreatePropertyModel(object instance, bool isEnumerable) { if (instance == null) { return(null); } // find the instance type var instanceType = isEnumerable ? TypeHelper.FindBiggestCommonType(instance as IEnumerable) : instance.GetType(); if (instanceType == null) { return(null); } // find all properties of the instance type var properties = isEnumerable ? TypeDescriptor.GetProperties(instanceType) : TypeDescriptor.GetProperties(instance); // The GetPropertyModel method does not return properties in a particular order, // such as alphabetical or declaration order. Your code must not depend on the // order in which properties are returned, because that order varies. TabViewModel currentTabViewModel = null; CategoryViewModel currentCategoryViewModel = null; Type currentComponentType = null; // Setting the default tab name // Use the type name of the Instance as the default tab name string tabName = DefaultTabName ?? instanceType.Name; // Setting the default category name string categoryName = DefaultCategoryName; propertyMap.Clear(); int sortOrder = 0; var result = new List <TabViewModel>(); foreach (PropertyDescriptor descriptor in properties) { if (descriptor == null) { continue; } // TODO: should not show attached dependency properties? if (DeclaredOnly && descriptor.ComponentType != instanceType) { continue; } if (descriptor.ComponentType != currentComponentType) { categoryName = DefaultCategoryName; tabName = DefaultTabName ?? descriptor.ComponentType.Name; currentComponentType = descriptor.ComponentType; } // Skip properties marked with [Browsable(false)] if (!descriptor.IsBrowsable) { continue; } // Read-only properties if (!ShowReadOnlyProperties && descriptor.IsReadOnly) { continue; } // If RequiredAttribute is set, skip properties that don't have the given attribute if (RequiredAttribute != null && !AttributeHelper.ContainsAttributeOfType(descriptor.Attributes, RequiredAttribute)) { continue; } // The default value for an Enum-property is the first enum in the enumeration. // If the first value happens to be filtered due to the attribute [Browsable(false)], // the WPF-binding system ends up in an infinite loop when updating the bound value // due to a PropertyChanged-call. We must therefore make sure that the initially selected // value is one of the allowed values from the filtered enumeration. if (descriptor.PropertyType.BaseType == typeof(Enum)) { List <object> validEnumValues = Enum.GetValues(descriptor.PropertyType).FilterOnBrowsableAttribute(); // Check if the enumeration that has all values hidden before accessing the first item. if (validEnumValues.Count > 0 && !validEnumValues.Contains(descriptor.GetValue(instance))) { descriptor.SetValue(instance, validEnumValues[0]); } } // Create Property ViewModel var propertyViewModel = PropertyViewModelFactory.CreateViewModel(instance, descriptor); propertyViewModel.IsEnumerable = isEnumerable; propertyViewModel.SubscribeValueChanged(); LocalizePropertyHeader(instanceType, propertyViewModel); propertyMap.Add(propertyViewModel.Name, propertyViewModel); propertyViewModel.PropertyChanged += OnPropertyChanged; if (propertyViewModel.SortOrder == int.MinValue) { propertyViewModel.SortOrder = sortOrder; } sortOrder = propertyViewModel.SortOrder; bool categoryFound = ParseTabAndCategory(descriptor, ref tabName, ref categoryName); if (!categoryFound && UseDefaultCategoryNameForUncategorizedProperties) { categoryName = DefaultCategoryName; tabName = DefaultTabName ?? descriptor.ComponentType.Name; } GetOrCreateTab(instanceType, result, tabName, sortOrder, ref currentTabViewModel, ref currentCategoryViewModel); GetOrCreateCategory(instanceType, categoryName, sortOrder, currentTabViewModel, ref currentCategoryViewModel); currentCategoryViewModel.Properties.Add(propertyViewModel); } // Check that properties used as optional properties are not Browsable CheckOptionalProperties(); // Sort the model using a stable sort algorithm return(SortPropertyModel(result)); }