/// <summary>
        /// Sets the attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="pi">The pi.</param>
        /// <param name="instance">The instance.</param>
        protected virtual void SetAttribute(Attribute attribute, PropertyItem pi, object instance)
        {
            var ssa = attribute as SelectorStyleAttribute;

            if (ssa != null)
            {
                pi.SelectorStyle = ssa.SelectorStyle;
            }

            var svpa = attribute as SelectedValuePathAttribute;

            if (svpa != null)
            {
                pi.SelectedValuePath = svpa.Path;
            }

            var f = attribute as FontAttribute;

            if (f != null)
            {
                pi.FontSize   = f.FontSize;
                pi.FontWeight = f.FontWeight;
                pi.FontFamily = f.FontFamily;
            }

            var fp = attribute as FontPreviewAttribute;

            if (fp != null)
            {
                pi.PreviewFonts = true;
                pi.FontSize     = fp.Size;
                pi.FontWeight   = fp.Weight;
                pi.FontFamilyPropertyDescriptor = pi.GetDescriptor(fp.FontFamilyPropertyName);
            }

            if (attribute is FontFamilySelectorAttribute)
            {
                pi.IsFontFamilySelector = true;
            }

            var ifpa = attribute as InputFilePathAttribute;

            if (ifpa != null)
            {
                pi.IsFilePath               = true;
                pi.IsFileOpenDialog         = true;
                pi.FilePathFilter           = ifpa.Filter;
                pi.FilePathDefaultExtension = ifpa.DefaultExtension;
            }

            var ofpa = attribute as OutputFilePathAttribute;

            if (ofpa != null)
            {
                pi.IsFilePath               = true;
                pi.IsFileOpenDialog         = false;
                pi.FilePathFilter           = ofpa.Filter;
                pi.FilePathDefaultExtension = ofpa.DefaultExtension;
            }

            if (attribute is DirectoryPathAttribute)
            {
                pi.IsDirectoryPath = true;
            }

            var da = attribute as DataTypeAttribute;

            if (da != null)
            {
                pi.DataTypes.Add(da.DataType);
                switch (da.DataType)
                {
                case DataType.MultilineText:
                    pi.AcceptsReturn = true;
                    break;

                case DataType.Password:
                    pi.IsPassword = true;
                    break;
                }
            }

            var ca = attribute as ColumnAttribute;

            if (ca != null)
            {
                pi.Columns.Add(ca);
            }

            var la = attribute as ListAttribute;

            if (la != null)
            {
                pi.ListCanAdd               = la.CanAdd;
                pi.ListCanRemove            = la.CanRemove;
                pi.ListMaximumNumberOfItems = la.MaximumNumberOfItems;
            }

            var ida = attribute as InputDirectionAttribute;

            if (ida != null)
            {
                pi.InputDirection = ida.InputDirection;
            }

            var eia = attribute as EasyInsertAttribute;

            if (eia != null)
            {
                pi.EasyInsert = eia.EasyInsert;
            }

            var sia = attribute as SortIndexAttribute;

            if (sia != null)
            {
                pi.SortIndex = sia.SortIndex;
            }

            var eba = attribute as EnableByAttribute;

            if (eba != null)
            {
                pi.IsEnabledDescriptor = pi.GetDescriptor(eba.PropertyName);
                pi.IsEnabledValue      = eba.PropertyValue;
            }

            var vba = attribute as VisibleByAttribute;

            if (vba != null)
            {
                pi.IsVisibleDescriptor = pi.GetDescriptor(vba.PropertyName);
            }

            var oa = attribute as OptionalAttribute;

            if (oa != null)
            {
                pi.IsOptional = true;
                if (oa.PropertyName != null)
                {
                    pi.OptionalDescriptor = pi.GetDescriptor(oa.PropertyName);
                }
            }

            var ra = attribute as EnableByRadioButtonAttribute;

            if (ra != null)
            {
                pi.RadioDescriptor = pi.GetDescriptor(ra.PropertyName);
                pi.RadioValue      = ra.Value;
            }

            if (attribute is CommentAttribute)
            {
                pi.IsComment = true;
            }

            if (attribute is ContentAttribute)
            {
                pi.IsContent = true;
            }

            var ea = attribute as EditableAttribute;

            if (ea != null)
            {
                pi.IsEditable = ea.AllowEdit;
            }

            if (attribute is AutoUpdateTextAttribute)
            {
                pi.AutoUpdateText = true;
            }

            var ispa = attribute as ItemsSourcePropertyAttribute;

            if (ispa != null)
            {
                pi.ItemsSourceDescriptor = pi.GetDescriptor(ispa.PropertyName);
            }

            var liispa = attribute as ListItemItemsSourcePropertyAttribute;

            if (liispa != null)
            {
                var p = TypeDescriptor.GetProperties(instance)[liispa.PropertyName];
                var listItemItemsSource = p != null?p.GetValue(instance) as IEnumerable : null;

                pi.ListItemItemsSource = listItemItemsSource;
            }

            var clpa = attribute as CheckableItemsAttribute;

            if (clpa != null)
            {
                pi.CheckableItemsIsCheckedPropertyName = clpa.IsCheckedPropertyName;
                pi.CheckableItemsContentPropertyName   = clpa.ContentPropertyName;
            }

            var rpa = attribute as BasePathPropertyAttribute;

            if (rpa != null)
            {
                pi.RelativePathDescriptor = pi.GetDescriptor(rpa.BasePathPropertyName);
            }

            var fa = attribute as FilterPropertyAttribute;

            if (fa != null)
            {
                pi.FilterDescriptor = pi.GetDescriptor(fa.PropertyName);
            }

            var dea = attribute as DefaultExtensionPropertyAttribute;

            if (dea != null)
            {
                pi.DefaultExtensionDescriptor = pi.GetDescriptor(dea.PropertyName);
            }

            var fsa = attribute as FormatStringAttribute;

            if (fsa != null)
            {
                pi.FormatString = fsa.FormatString;
            }

            var coa = attribute as ConverterAttribute;

            if (coa != null)
            {
                pi.Converter = Activator.CreateInstance(coa.ConverterType) as IValueConverter;
            }

            var sa = attribute as SlidableAttribute;

            if (sa != null)
            {
                pi.IsSlidable          = true;
                pi.SliderMinimum       = sa.Minimum;
                pi.SliderMaximum       = sa.Maximum;
                pi.SliderSmallChange   = sa.SmallChange;
                pi.SliderLargeChange   = sa.LargeChange;
                pi.SliderSnapToTicks   = sa.SnapToTicks;
                pi.SliderTickFrequency = sa.TickFrequency;
            }

            var spa = attribute as SpinnableAttribute;

            if (spa != null)
            {
                pi.IsSpinnable     = true;
                pi.SpinMinimum     = spa.Minimum;
                pi.SpinMaximum     = spa.Maximum;
                pi.SpinSmallChange = spa.SmallChange;
                pi.SpinLargeChange = spa.LargeChange;
            }

            var wpa = attribute as WidePropertyAttribute;

            if (wpa != null)
            {
                pi.HeaderPlacement = wpa.ShowHeader ? HeaderPlacement.Above : HeaderPlacement.Hidden;
            }

            var wia = attribute as WidthAttribute;

            if (wia != null)
            {
                pi.Width = wia.Width;
            }

            var hpa = attribute as HeaderPlacementAttribute;

            if (hpa != null)
            {
                pi.HeaderPlacement = hpa.HeaderPlacement;
            }

            var ha = attribute as HorizontalAlignmentAttribute;

            if (ha != null)
            {
                pi.HorizontalAlignment = ha.HorizontalAlignment;
            }

            var hea = attribute as HeightAttribute;

            if (hea != null)
            {
                pi.Height        = hea.Height;
                pi.MinimumHeight = hea.MinimumHeight;
                pi.MaximumHeight = hea.MaximumHeight;
                pi.AcceptsReturn = true;
            }

            var fta = attribute as FillTabAttribute;

            if (fta != null)
            {
                pi.FillTab       = true;
                pi.AcceptsReturn = true;
            }
        }
        /// <summary>
        /// Sets the attribute.
        /// </summary>
        /// <param name="attribute">The attribute.</param>
        /// <param name="pi">The pi.</param>
        /// <param name="instance">The instance.</param>
        protected virtual void SetAttribute(Attribute attribute, PropertyItem pi, object instance)
        {
            var ssa = attribute as SelectorStyleAttribute;

            if (ssa != null)
            {
                pi.SelectorStyle = ssa.SelectorStyle;
            }

            var svpa = attribute as SelectedValuePathAttribute;

            if (svpa != null)
            {
                pi.SelectedValuePath = svpa.Path;
            }

            var dmpa = attribute as DisplayMemberPathAttribute;

            if (dmpa != null)
            {
                pi.DisplayMemberPath = dmpa.Path;
            }

            var f = attribute as FontAttribute;

            if (f != null)
            {
                pi.FontSize   = f.FontSize;
                pi.FontWeight = f.FontWeight;
                pi.FontFamily = f.FontFamily;
            }

            var fp = attribute as FontPreviewAttribute;

            if (fp != null)
            {
                pi.PreviewFonts = true;
                pi.FontSize     = fp.Size;
                pi.FontWeight   = fp.Weight;
                pi.FontFamilyPropertyDescriptor = pi.GetDescriptor(fp.FontFamilyPropertyName);
            }

            if (attribute is FontFamilySelectorAttribute)
            {
                pi.IsFontFamilySelector = true;
            }

            var ifpa = attribute as InputFilePathAttribute;

            if (ifpa != null)
            {
                pi.IsFilePath               = true;
                pi.IsFileOpenDialog         = true;
                pi.FilePathFilter           = ifpa.Filter;
                pi.FilePathDefaultExtension = ifpa.DefaultExtension;
            }

            var ofpa = attribute as OutputFilePathAttribute;

            if (ofpa != null)
            {
                pi.IsFilePath               = true;
                pi.IsFileOpenDialog         = false;
                pi.FilePathFilter           = ofpa.Filter;
                pi.FilePathDefaultExtension = ofpa.DefaultExtension;
            }

            if (attribute is DirectoryPathAttribute)
            {
                pi.IsDirectoryPath = true;
            }

            var da = attribute as DataTypeAttribute;

            if (da != null)
            {
                pi.DataTypes.Add(da.DataType);
                switch (da.DataType)
                {
                case DataType.MultilineText:
                    pi.AcceptsReturn = true;
                    break;

                case DataType.Password:
                    pi.IsPassword = true;
                    break;
                }
            }

            var cpa = attribute as ColumnsPropertyAttribute;

            if (cpa != null)
            {
                var descriptor = pi.GetDescriptor(cpa.PropertyName);
                var columns    = descriptor?.GetValue(instance) as IEnumerable <Column>;

                if (columns != null)
                {
                    var glc = new GridLengthConverter();
                    foreach (Column column in columns)
                    {
                        var cd = new ColumnDefinition
                        {
                            PropertyName        = column.PropertyName,
                            Header              = column.Header,
                            FormatString        = column.FormatString,
                            Width               = (GridLength)(glc.ConvertFromInvariantString(column.Width) ?? GridLength.Auto),
                            IsReadOnly          = column.IsReadOnly,
                            HorizontalAlignment = StringUtilities.ToHorizontalAlignment(column.Alignment.ToString(CultureInfo.InvariantCulture))
                        };

                        if (column.ItemsSourcePropertyName != null)
                        {
                            // use instance.GetType to be able to fetch static properties also
                            var p = instance.GetType().GetProperties().FirstOrDefault(x => x.Name == column.ItemsSourcePropertyName);
                            cd.ItemsSource = p?.GetValue(instance) as IEnumerable;
                        }

                        pi.Columns.Add(cd);
                    }
                }
            }

            var la = attribute as ListAttribute;

            if (la != null)
            {
                pi.ListCanAdd               = la.CanAdd;
                pi.ListCanRemove            = la.CanRemove;
                pi.ListMaximumNumberOfItems = la.MaximumNumberOfItems;
            }

            var ida = attribute as InputDirectionAttribute;

            if (ida != null)
            {
                pi.InputDirection = ida.InputDirection;
            }

            var eia = attribute as EasyInsertAttribute;

            if (eia != null)
            {
                pi.IsEasyInsertByKeyboardEnabled = eia.EasyInsertByKeyboard;
                pi.IsEasyInsertByMouseEnabled    = eia.EasyInsertByMouse;
            }

            var sia = attribute as SortIndexAttribute;

            if (sia != null)
            {
                pi.SortIndex = sia.SortIndex;
            }

            var eba = attribute as EnableByAttribute;

            if (eba != null)
            {
                pi.IsEnabledDescriptor = pi.GetDescriptor(eba.PropertyName);
                pi.IsEnabledValue      = eba.PropertyValue;
            }

            var vba = attribute as VisibleByAttribute;

            if (vba != null)
            {
                pi.IsVisibleDescriptor = pi.GetDescriptor(vba.PropertyName);
                pi.IsVisibleValue      = vba.PropertyValue;
            }

            var oa = attribute as OptionalAttribute;

            if (oa != null)
            {
                pi.IsOptional = true;
                if (oa.PropertyName != null)
                {
                    pi.OptionalDescriptor = pi.GetDescriptor(oa.PropertyName);
                }
            }

            var ila = attribute as IndentationLevelAttribute;

            if (ila != null)
            {
                pi.IndentationLevel = ila.IndentationLevel;
            }

            var ra = attribute as EnableByRadioButtonAttribute;

            if (ra != null)
            {
                pi.RadioDescriptor = pi.GetDescriptor(ra.PropertyName);
                pi.RadioValue      = ra.Value;
            }

            if (attribute is CommentAttribute)
            {
                pi.IsComment = true;
            }

            if (attribute is ContentAttribute)
            {
                pi.IsContent = true;
            }

            var ea = attribute as System.ComponentModel.DataAnnotations.EditableAttribute;

            if (ea != null)
            {
                pi.IsEditable = ea.AllowEdit;
            }

            var ea2 = attribute as DataAnnotations.EditableAttribute;

            if (ea2 != null)
            {
                pi.IsEditable = ea2.AllowEdit;
            }

            if (attribute is AutoUpdateTextAttribute)
            {
                pi.AutoUpdateText = true;
            }

            var ispa = attribute as ItemsSourcePropertyAttribute;

            if (ispa != null)
            {
                pi.ItemsSourceDescriptor = pi.GetDescriptor(ispa.PropertyName);
            }

            var liispa = attribute as ListItemItemsSourcePropertyAttribute;

            if (liispa != null)
            {
                var p = TypeDescriptor.GetProperties(instance)[liispa.PropertyName];
                var listItemItemsSource = p != null?p.GetValue(instance) as IEnumerable : null;

                pi.ListItemItemsSource = listItemItemsSource;
            }

            var clpa = attribute as CheckableItemsAttribute;

            if (clpa != null)
            {
                pi.CheckableItemsIsCheckedPropertyName = clpa.IsCheckedPropertyName;
                pi.CheckableItemsContentPropertyName   = clpa.ContentPropertyName;
            }

            var rpa = attribute as BasePathPropertyAttribute;

            if (rpa != null)
            {
                pi.RelativePathDescriptor = pi.GetDescriptor(rpa.BasePathPropertyName);
            }

            var fa = attribute as FilterPropertyAttribute;

            if (fa != null)
            {
                pi.FilterDescriptor = pi.GetDescriptor(fa.PropertyName);
            }

            var dea = attribute as DefaultExtensionPropertyAttribute;

            if (dea != null)
            {
                pi.DefaultExtensionDescriptor = pi.GetDescriptor(dea.PropertyName);
            }

            var fsa = attribute as FormatStringAttribute;

            if (fsa != null)
            {
                pi.FormatString = fsa.FormatString;
            }

            var coa = attribute as ConverterAttribute;

            if (coa != null)
            {
                pi.Converter = Activator.CreateInstance(coa.ConverterType) as IValueConverter;
            }

            var sa = attribute as SlidableAttribute;

            if (sa != null)
            {
                pi.IsSlidable          = true;
                pi.SliderMinimum       = sa.Minimum;
                pi.SliderMaximum       = sa.Maximum;
                pi.SliderSmallChange   = sa.SmallChange;
                pi.SliderLargeChange   = sa.LargeChange;
                pi.SliderSnapToTicks   = sa.SnapToTicks;
                pi.SliderTickFrequency = sa.TickFrequency;
            }

            var spa = attribute as SpinnableAttribute;

            if (spa != null)
            {
                pi.IsSpinnable     = true;
                pi.SpinMinimum     = spa.Minimum;
                pi.SpinMaximum     = spa.Maximum;
                pi.SpinSmallChange = spa.SmallChange;
                pi.SpinLargeChange = spa.LargeChange;
            }

            var wpa = attribute as WidePropertyAttribute;

            if (wpa != null)
            {
                pi.HeaderPlacement = wpa.ShowHeader ? HeaderPlacement.Above : HeaderPlacement.Hidden;
            }

            var wia = attribute as WidthAttribute;

            if (wia != null)
            {
                pi.Width = wia.Width;
            }

            var hpa = attribute as HeaderPlacementAttribute;

            if (hpa != null)
            {
                pi.HeaderPlacement = hpa.HeaderPlacement;
            }

            var ha = attribute as HorizontalAlignmentAttribute;

            if (ha != null)
            {
                pi.HorizontalAlignment = ha.HorizontalAlignment;
            }

            var hea = attribute as HeightAttribute;

            if (hea != null)
            {
                pi.Height        = hea.Height;
                pi.MinimumHeight = hea.MinimumHeight;
                pi.MaximumHeight = hea.MaximumHeight;
                pi.AcceptsReturn = true;
            }

            var fta = attribute as FillTabAttribute;

            if (fta != null)
            {
                pi.FillTab       = true;
                pi.AcceptsReturn = true;
            }
        }
        /// <summary>
        /// Sets the properties.
        /// </summary>
        /// <param name="pi">The property item.</param>
        /// <param name="instance">The instance.</param>
        protected virtual void SetProperties(PropertyItem pi, object instance)
        {
            var tabName      = this.DefaultTabName ?? instance.GetType().Name;
            var categoryName = this.DefaultCategoryName;

            // find the declaring type
            var declaringType = pi.Descriptor.ComponentType;
            var propertyInfo  = instance.GetType().GetProperty(pi.Descriptor.Name);

            if (propertyInfo != null)
            {
                declaringType = propertyInfo.DeclaringType;
            }

            if (declaringType != this.CurrentDeclaringType)
            {
                this.CurrentCategory = null;
            }

            this.CurrentDeclaringType = declaringType;

            if (!this.InheritCategories)
            {
                this.CurrentCategory = null;
            }

            var ca = pi.GetAttribute <System.ComponentModel.CategoryAttribute>();

            if (ca != null)
            {
                this.CurrentCategory = ca.Category;
                this.CurrentCategoryDeclaringType = declaringType;
            }

            var ca2 = pi.GetAttribute <DataAnnotations.CategoryAttribute>();

            if (ca2 != null)
            {
                this.CurrentCategory = ca2.Category;
                this.CurrentCategoryDeclaringType = declaringType;
            }

            var category = this.CurrentCategory ?? (this.DefaultCategoryName ?? this.GetCategory(pi.Descriptor, declaringType));

            if (category != null)
            {
                var items = category.Split('|');
                if (items.Length == 2)
                {
                    tabName      = items[0];
                    categoryName = items[1];
                }

                if (items.Length == 1)
                {
                    categoryName = items[0];
                }
            }

            var displayName = this.GetDisplayName(pi.Descriptor, declaringType);
            var description = this.GetDescription(pi.Descriptor, declaringType);

            // Localize the strings
            pi.DisplayName = this.GetLocalizedString(displayName, declaringType);
            pi.Description = this.GetLocalizedDescription(description, declaringType);
            pi.Category    = this.GetLocalizedString(categoryName, this.CurrentCategoryDeclaringType);
            pi.Tab         = this.GetLocalizedString(tabName, this.CurrentCategoryDeclaringType);

            pi.IsReadOnly = pi.Descriptor.IsReadOnly();

            // Find descriptors by convention
            pi.IsEnabledDescriptor = pi.GetDescriptor(string.Format(this.EnabledPattern, pi.PropertyName));
            pi.IsVisibleDescriptor = pi.GetDescriptor(string.Format(this.VisiblePattern, pi.PropertyName));
            pi.OptionalDescriptor  = pi.GetDescriptor(string.Format(this.OptionalPattern, pi.PropertyName));

            foreach (Attribute attribute in pi.Descriptor.Attributes)
            {
                this.SetAttribute(attribute, pi, instance);
            }

            pi.IsOptional = pi.IsOptional || pi.OptionalDescriptor != null;

            if (pi.Descriptor.PropertyType == typeof(TimeSpan) && pi.Converter == null)
            {
                pi.Converter          = new TimeSpanToStringConverter();
                pi.ConverterParameter = pi.FormatString;
            }
        }
        /// <summary>
        /// Sets the properties.
        /// </summary>
        /// <param name="pi">
        /// The property item.
        /// </param>
        protected virtual void SetProperties(PropertyItem pi)
        {
            var pd         = pi.Descriptor;
            var properties = pi.Properties;

            var tabName      = this.DefaultTabName ?? pi.Instance.GetType().Name;
            var categoryName = this.DefaultCategoryName;

            // find the declaring type
            Type declaringType = pi.Descriptor.ComponentType;
            var  propertyInfo  = pi.Instance.GetType().GetProperty(pi.Descriptor.Name);

            if (propertyInfo != null)
            {
                declaringType = propertyInfo.DeclaringType;
            }

            if (declaringType != this.CurrentDeclaringType)
            {
                this.CurrentCategory = null;
            }

            this.CurrentDeclaringType = declaringType;

            if (!this.InheritCategories)
            {
                this.CurrentCategory = null;
            }

            var ca = AttributeHelper.GetFirstAttribute <CategoryAttribute>(pd);

            if (ca != null)
            {
                this.CurrentCategory = ca.Category;
                this.CurrentCategoryDeclaringType = declaringType;
            }

            var category = this.CurrentCategory ?? (this.DefaultCategoryName ?? pd.Category);

            if (category != null)
            {
                var items = category.Split('|');
                if (items.Length == 2)
                {
                    tabName      = items[0];
                    categoryName = items[1];
                }

                if (items.Length == 1)
                {
                    categoryName = items[0];
                }
            }

            var displayName = this.GetDisplayName(pd, declaringType);
            var description = this.GetDescription(pd, declaringType);

            pi.DisplayName = this.GetLocalizedString(displayName, declaringType);
            pi.Description = this.GetLocalizedDescription(description, declaringType);

            pi.Category            = this.GetLocalizedString(categoryName, this.CurrentCategoryDeclaringType);
            pi.CategoryDescription = this.GetLocalizedDescription(categoryName, this.CurrentCategoryDeclaringType);
            pi.Tab            = this.GetLocalizedString(tabName, this.CurrentCategoryDeclaringType);
            pi.TabDescription = this.GetLocalizedDescription(tabName, this.CurrentCategoryDeclaringType);

            // Find descriptors by convention
            pi.IsEnabledDescriptor = pi.GetDescriptor(string.Format(this.EnabledPattern, pd.Name));
            pi.IsVisibleDescriptor = pi.GetDescriptor(string.Format(this.VisiblePattern, pd.Name));
            pi.OptionalDescriptor  = pi.GetDescriptor(string.Format(this.OptionalPattern, pd.Name));

            pi.UseRadioButtons = pi.GetAttribute <RadioButtonsAttribute>() != null;
            var fp = pi.GetAttribute <FontPreviewAttribute>();

            pi.PreviewFonts = fp != null;
            if (fp != null)
            {
                pi.FontSize   = fp.Size;
                pi.FontWeight = fp.Weight;
                pi.FontFamilyPropertyDescriptor = pi.GetDescriptor(fp.FontFamilyPropertyName);
            }

            var fpa = pi.GetAttribute <FilePathAttribute>();

            pi.IsFilePath = fpa != null;
            if (fpa != null)
            {
                pi.FilePathFilter           = fpa.Filter;
                pi.FilePathDefaultExtension = fpa.DefaultExtension;
                pi.IsFileOpenDialog         = fpa.UseOpenDialog;
            }

            var dpa = pi.GetAttribute <DirectoryPathAttribute>();

            pi.IsDirectoryPath = dpa != null;

            foreach (var da in pi.GetAttributes <DataTypeAttribute>())
            {
                pi.DataTypes.Add(da.DataType);
                switch (da.DataType)
                {
                case DataType.MultilineText:
                    pi.AcceptsReturn = true;
                    break;

                case DataType.Password:
                    pi.IsPassword = true;
                    break;
                }
            }

            foreach (var da in pi.GetAttributes <ColumnAttribute>())
            {
                pi.Columns.Add(da);
            }

            var la = pi.GetAttribute <ListAttribute>();

            if (la != null)
            {
                pi.ListCanAdd               = la.CanAdd;
                pi.ListCanRemove            = la.CanRemove;
                pi.ListMaximumNumberOfItems = la.MaximumNumberOfItems;
            }

            var sia = pi.GetAttribute <SortIndexAttribute>();

            if (sia != null)
            {
                pi.SortIndex = sia.SortIndex;
            }

            var eba = pi.GetAttribute <EnableByAttribute>();

            if (eba != null)
            {
                pi.IsEnabledDescriptor = properties.Find(eba.PropertyName, false);
            }

            var vba = pi.GetAttribute <VisibleByAttribute>();

            if (vba != null)
            {
                pi.IsVisibleDescriptor = properties.Find(vba.PropertyName, false);
            }

            if (pi.Is(typeof(IList)))
            {
                pi.MinimumHeight   = 100;
                pi.MaximumHeight   = 240;
                pi.HeaderPlacement = HeaderPlacement.Above;
            }

            pi.IsOptional = pi.OptionalDescriptor != null;

            var oa = pi.GetAttribute <OptionalAttribute>();

            if (oa != null)
            {
                if (oa.PropertyName != null)
                {
                    pi.OptionalDescriptor = properties.Find(oa.PropertyName, false);
                }

                pi.IsOptional = true;
            }

            pi.IsComment = pi.GetAttribute <CommentAttribute>() != null;
            if (pi.IsComment)
            {
                pi.HeaderPlacement = HeaderPlacement.Hidden;
            }

            pi.IsEditable = pi.GetAttribute <IsEditableAttribute>() != null;

            pi.AutoUpdateText = pi.GetAttribute <AutoUpdateTextAttribute>() != null;

            var ispa = pi.GetAttribute <ItemsSourcePropertyAttribute>();

            if (ispa != null)
            {
                pi.ItemsSourceDescriptor = properties.Find(ispa.PropertyName, false);
            }

            var rpa = pi.GetAttribute <BasePathPropertyAttribute>();

            if (rpa != null)
            {
                pi.RelativePathDescriptor = properties.Find(rpa.BasePathPropertyName, false);
            }

            var fa = pi.GetAttribute <FilterPropertyAttribute>();

            if (fa != null)
            {
                pi.FilterDescriptor = properties.Find(fa.PropertyName, false);
            }

            var fsa = pi.GetAttribute <FormatStringAttribute>();

            if (fsa != null)
            {
                pi.FormatString = fsa.FormatString;
            }

            var coa = pi.GetAttribute <ConverterAttribute>();

            if (coa != null)
            {
                pi.Converter = Activator.CreateInstance(coa.ConverterType) as IValueConverter;
            }

            var sa = pi.GetAttribute <SlidableAttribute>();

            if (sa != null)
            {
                pi.IsSlidable          = true;
                pi.SliderMinimum       = sa.Minimum;
                pi.SliderMaximum       = sa.Maximum;
                pi.SliderSmallChange   = sa.SmallChange;
                pi.SliderLargeChange   = sa.LargeChange;
                pi.SliderSnapToTicks   = sa.SnapToTicks;
                pi.SliderTickFrequency = sa.TickFrequency;
            }

            var spa = pi.GetAttribute <SpinnableAttribute>();

            if (spa != null)
            {
                pi.IsSpinnable     = true;
                pi.SpinMinimum     = spa.Minimum;
                pi.SpinMaximum     = spa.Maximum;
                pi.SpinSmallChange = spa.SmallChange;
                pi.SpinLargeChange = spa.LargeChange;
            }

            var wpa = pi.GetAttribute <WidePropertyAttribute>();

            if (wpa != null)
            {
                pi.HeaderPlacement = wpa.ShowHeader ? HeaderPlacement.Above : HeaderPlacement.Hidden;
            }

            var wia = pi.GetAttribute <WidthAttribute>();

            if (wia != null)
            {
                pi.Width = wia.Width;
            }

            var hpa = pi.GetAttribute <HeaderPlacementAttribute>();

            if (hpa != null)
            {
                pi.HeaderPlacement = hpa.HeaderPlacement;
            }

            var ha = pi.GetAttribute <HeightAttribute>();

            if (ha != null)
            {
                pi.Height        = ha.Height;
                pi.MinimumHeight = ha.MinimumHeight;
                pi.MaximumHeight = ha.MaximumHeight;
                pi.AcceptsReturn = true;
            }
        }