/// <summary>
        /// Creates the grid control.
        /// </summary>
        /// <param name="property">
        /// The property.
        /// </param>
        /// <returns>
        /// The control.
        /// </returns>
        protected FrameworkElement CreateGridControl(PropertyItem property)
        {
            var c = new SimpleGrid { CanDelete = property.ListCanRemove, CanInsert = property.ListCanAdd };

            var glc = new GridLengthConverter();
            foreach (var ca in property.Columns.OrderBy(cd => cd.ColumnIndex))
            {
                var cd = new ColumnDefinition
                    {
                        DataField = ca.PropertyName,
                        Header = ca.Header,
                        FormatString = ca.FormatString,
                        Width = (GridLength)glc.ConvertFromInvariantString(ca.Width)
                    };
                switch (ca.Alignment.ToString().ToUpper())
                {
                    case "L":
                        cd.HorizontalAlignment = HorizontalAlignment.Left;
                        break;
                    case "R":
                        cd.HorizontalAlignment = HorizontalAlignment.Right;
                        break;
                    default:
                        cd.HorizontalAlignment = HorizontalAlignment.Center;
                        break;
                }

                c.ColumnDefinitions.Add(cd);
            }

            c.SetBinding(SimpleGrid.ContentProperty, property.CreateBinding());
            return c;
        }
        /// <summary>
        /// Creates the grid control.
        /// </summary>
        /// <param name="property">The property.</param>
        /// <returns>
        /// The control.
        /// </returns>
        protected virtual FrameworkElement CreateGridControl(PropertyItem property)
        {
            var c = new DataGrid
            {
                CanDelete = property.ListCanRemove,
                CanInsert = property.ListCanAdd,
                InputDirection = property.InputDirection,
                EasyInsert = property.EasyInsert,
                AutoGenerateColumns = property.Columns.Count == 0
            };

            var glc = new GridLengthConverter();
            foreach (var ca in property.Columns.OrderBy(cd => cd.ColumnIndex))
            {
                var cd = new ColumnDefinition
                    {
                        PropertyName = ca.PropertyName,
                        Header = ca.Header,
                        FormatString = ca.FormatString,
                        Width = (GridLength)(glc.ConvertFromInvariantString(ca.Width) ?? GridLength.Auto),
                        IsReadOnly = ca.IsReadOnly
                    };

                if (ca.PropertyName == string.Empty && property.ListItemItemsSource != null)
                {
                    cd.ItemsSource = property.ListItemItemsSource;
                }

                switch (ca.Alignment.ToString(CultureInfo.InvariantCulture).ToUpper())
                {
                    case "L":
                        cd.HorizontalAlignment = HorizontalAlignment.Left;
                        break;
                    case "R":
                        cd.HorizontalAlignment = HorizontalAlignment.Right;
                        break;
                    default:
                        cd.HorizontalAlignment = HorizontalAlignment.Center;
                        break;
                }

                c.ColumnDefinitions.Add(cd);
            }

            c.SetBinding(DataGrid.ItemsSourceProperty, property.CreateBinding());
            return c;
        }
        /// <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)
            {
                var glc = new GridLengthConverter();
                var cd = new ColumnDefinition
                {
                    PropertyName = ca.PropertyName,
                    Header = ca.Header,
                    FormatString = ca.FormatString,
                    Width = (GridLength)(glc.ConvertFromInvariantString(ca.Width) ?? GridLength.Auto),
                    IsReadOnly = ca.IsReadOnly,
                    HorizontalAlignment = StringUtilities.ToHorizontalAlignment(ca.Alignment.ToString(CultureInfo.InvariantCulture))
                };

                // TODO: sort by index
                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.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);
                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 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;
            }
        }