public static void FreezeAll(this FormDefinition definition)
 {
     definition.Freeze();
     foreach (var element in definition.FormRows.SelectMany(r => r.Elements).SelectMany(c => c.Elements))
     {
         element.Freeze();
     }
 }
예제 #2
0
        private FormDefinition BuildDefinition(Type type)
        {
            // Only classes are allowed.
            // Primitives should be retrieved from prebuilt definitions.
            if (!type.IsClass || typeof(MulticastDelegate).IsAssignableFrom(type.BaseType))
            {
                return(null);
            }

            var formDefinition    = new FormDefinition(type);
            var mode              = DefaultFields.AllExcludingReadonly;
            var grid              = new[] { 1d };
            var beforeFormContent = new List <AttrElementTuple>();
            var afterFormContent  = new List <AttrElementTuple>();

            foreach (var attribute in type.GetCustomAttributes())
            {
                switch (attribute)
                {
                case ResourceAttribute resource:
                    formDefinition.Resources.Add(resource.Name, resource.Value is string expr
                            ? (IValueProvider)BoundExpression.Parse(expr)
                            : new LiteralValue(resource.Value));
                    break;

                case FormAttribute form:
                    mode = form.Mode;
                    grid = form.Grid;
                    if (grid == null || grid.Length < 1)
                    {
                        grid = new[] { 1d };
                    }

                    break;

                case FormContentAttribute contentAttribute:
                    if (contentAttribute.Placement == Placement.After)
                    {
                        afterFormContent.Add(new AttrElementTuple(contentAttribute, contentAttribute.GetElement()));
                    }
                    else if (contentAttribute.Placement == Placement.Before)
                    {
                        beforeFormContent.Add(new AttrElementTuple(contentAttribute,
                                                                   contentAttribute.GetElement()));
                    }

                    break;

                case MetaAttribute meta:
                    if (!string.IsNullOrEmpty(meta.Name))
                    {
                        formDefinition.Metadata[meta.Name] = meta.Value;
                    }

                    break;
                }
            }

            beforeFormContent.Sort((a, b) => a.Attr.Position.CompareTo(b.Attr.Position));
            afterFormContent.Sort((a, b) => a.Attr.Position.CompareTo(b.Attr.Position));

            var gridLength = grid.Length;

            // Pass one - get list of valid properties.
            var properties = Utilities
                             .GetProperties(type, mode)
                             .Select(p => new PropertyInfoWrapper(p))
                             .ToArray();

            // Pass two - build form elements.
            var elements = new List <ElementWrapper>();

            foreach (var property in properties)
            {
                var deserializer = TryGetDeserializer(property.PropertyType);
                // Query property builders.
                var element = Build(property, deserializer);

                if (element == null)
                {
                    // Unhandled properties are ignored.
                    continue;
                }

                // Pass three - initialize elements.
                foreach (var initializer in FieldInitializers)
                {
                    initializer.Initialize(element, property, deserializer);
                }

                var wrapper = new ElementWrapper(element, property);
                // Set layout.
                var attr = property.GetCustomAttribute <FieldAttribute>();
                if (attr != null)
                {
                    wrapper.Position   = attr.Position;
                    wrapper.Row        = attr.Row;
                    wrapper.Column     = attr.Column;
                    wrapper.ColumnSpan = attr.ColumnSpan;
                }

                elements.Add(wrapper);
            }

            // Pass four - order elements.
            elements = elements.OrderBy(element => element.Position).ToList();

            // Pass five - group rows and calculate layout.
            var layout = PerformLayout(grid, elements);

            // Pass six - add attached elements.
            var rows = new List <FormRow>();

            // Before form.
            rows.AddRange(CreateRows(beforeFormContent, gridLength));

            foreach (var row in layout)
            {
                var before = new List <AttrElementTuple>();
                var after  = new List <AttrElementTuple>();
                foreach (var element in row.Elements)
                {
                    var property = element.Property;
                    foreach (var attr in property.GetCustomAttributes <FormContentAttribute>())
                    {
                        if (attr.Placement == Placement.Before)
                        {
                            before.Add(new AttrElementTuple(attr, attr.GetElement()));
                        }
                        else if (attr.Placement == Placement.After)
                        {
                            after.Add(new AttrElementTuple(attr, attr.GetElement()));
                        }
                    }
                }

                before.Sort((a, b) => a.Attr.Position.CompareTo(b.Attr.Position));
                after.Sort((a, b) => a.Attr.Position.CompareTo(b.Attr.Position));

                // Before element.
                rows.AddRange(CreateRows(before, gridLength));

                // Field row.
                var formRow = new FormRow();
                formRow.Elements.AddRange(
                    row.Elements.Select(w =>
                {
                    var inlineElements = w.Property
                                         .GetCustomAttributes <FormContentAttribute>()
                                         .Where(attr => attr.Placement == Placement.Inline)
                                         .Select(attr => new AttrElementTuple(attr, attr.GetElement()))
                                         .OrderBy(tuple => tuple.Attr.Position)
                                         .ToList();

                    w.Element.LinePosition = (Position)(-1);
                    if (inlineElements.Count != 0)
                    {
                        return(new FormElementContainer(w.Column, w.ColumnSpan,
                                                        inlineElements
                                                        .Select(t => t.Element)
                                                        .Concat(new[] { w.Element })
                                                        .ToList()));
                    }

                    return(new FormElementContainer(w.Column, w.ColumnSpan, w.Element));
                }));
                rows.Add(formRow);

                // After element.
                rows.AddRange(CreateRows(after, gridLength));
            }

            // After form.
            rows.AddRange(CreateRows(afterFormContent, gridLength));

            // Wrap up everything.
            formDefinition.Grid     = grid;
            formDefinition.FormRows = rows;
            formDefinition.Freeze();
            foreach (var element in formDefinition.FormRows.SelectMany(r => r.Elements).SelectMany(c => c.Elements))
            {
                element.Freeze();
            }

            return(formDefinition);
        }