/// <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)); }
public override void GenerateColumnDefinitions() { var list = this.ItemsSource; if (list == null) { return; } var view = CollectionViewSource.GetDefaultView(this.ItemsSource); var iitemProperties = view as IItemProperties; if (iitemProperties != null && iitemProperties.ItemProperties.Count > 0) { foreach (var info in iitemProperties.ItemProperties) { var descriptor = info.Descriptor as PropertyDescriptor; if (!descriptor.IsBrowsable) { continue; } Owner.ColumnDefinitions.Add( new ColumnDefinition { Descriptor = descriptor, Header = info.Name, HorizontalAlignment = Owner.DefaultHorizontalAlignment, Width = Owner.DefaultColumnWidth }); } return; } var itemType = TypeHelper.FindBiggestCommonType(list); var properties = TypeDescriptor.GetProperties(itemType); if (properties.Count == 0) { // Otherwise try to get the property descriptors from an instance properties = GetPropertiesFromInstance(list, itemType); } foreach (PropertyDescriptor descriptor in properties) { if (!descriptor.IsBrowsable) { continue; } Owner.ColumnDefinitions.Add( new ColumnDefinition { Descriptor = descriptor, Header = descriptor.Name, HorizontalAlignment = Owner.DefaultHorizontalAlignment, Width = Owner.DefaultColumnWidth }); } if (Owner.ColumnDefinitions.Count == 0) { var itemsType = TypeHelper.GetItemType(list); Owner.ColumnDefinitions.Add( new ColumnDefinition { PropertyType = itemsType, Header = itemsType.Name, HorizontalAlignment = Owner.DefaultHorizontalAlignment, Width = Owner.DefaultColumnWidth }); } }
/// <summary> /// Initializes a new instance of the <see cref="ItemsBag"/> class. /// </summary> /// <param name="objects"> /// The objects. /// </param> public ItemsBag(IEnumerable objects) { this.Objects = objects; this.BiggestType = TypeHelper.FindBiggestCommonType(objects); this.Subscribe(); }
/// <summary> /// Gets the type of the items in the items source. /// </summary> /// <param name="itemsSource">The items source.</param> /// <returns>The type.</returns> protected Type GetItemType(IList itemsSource) { // iterate to find the biggest common type return(TypeHelper.FindBiggestCommonType(itemsSource)); }
/// <summary> /// Generate column definitions based on a list of items. /// </summary> /// <param name="list">The list of items.</param> /// <returns>A sequence of column definitions.</returns> /// <remarks>The constraint is that all the items in the ItemsSource's should be of the same type. /// For non built in type, a /// <code>public static T Parse(string s, IFormatProvider formatProvider)</code> and /// <code>public string ToString(string format, IFormatProvider formatProvider)</code> should be defined. /// interface type is not acceptable for no object instance can be created based on it.</remarks> protected override IEnumerable <ColumnDefinition> GenerateColumnDefinitions(IList list) { if (list == null) { yield break; } // Strategy 1: get properties from IItemProperties var view = CollectionViewSource.GetDefaultView(list); var itemPropertiesView = view as IItemProperties; if (itemPropertiesView?.ItemProperties != null && itemPropertiesView.ItemProperties.Count > 0) { foreach (var info in itemPropertiesView.ItemProperties) { var descriptor = info.Descriptor as PropertyDescriptor; if (descriptor == null || !descriptor.IsBrowsable) { continue; } var cd = new ColumnDefinition { PropertyName = descriptor.Name, Header = info.Name, HorizontalAlignment = this.DefaultHorizontalAlignment, Width = this.DefaultColumnWidth }; yield return(cd); } yield break; } // Strategy 2: get properties from type descriptor var itemType = TypeHelper.FindBiggestCommonType(list); var properties = TypeDescriptor.GetProperties(itemType); if (properties.Count == 0) { // Otherwise try to get the property descriptors from an instance properties = GetPropertiesFromInstance(list, itemType); } if (properties.Count > 0) { foreach (PropertyDescriptor descriptor in properties) { if (!descriptor.IsBrowsable) { continue; } var cd = new ColumnDefinition { PropertyName = descriptor.Name, Header = descriptor.Name, HorizontalAlignment = this.DefaultHorizontalAlignment, Width = this.DefaultColumnWidth }; yield return(cd); } yield break; } // Strategy 3: create a single column var itemsType = TypeHelper.GetItemType(list); yield return (new ColumnDefinition { Header = itemsType.Name, HorizontalAlignment = this.DefaultHorizontalAlignment, Width = this.DefaultColumnWidth }); }
/// <summary> /// Initializes a new instance of the <see cref="ItemsBag" /> class. /// </summary> /// <param name="objects">The objects.</param> public ItemsBag(IEnumerable objects) { this.Objects = objects as object[] ?? objects.Cast <object>().ToArray(); this.BiggestType = TypeHelper.FindBiggestCommonType(this.Objects); this.Subscribe(); }