# DetailViewLayoutBuilders - ModelBuilder Syntax

DetailViewLayoutBuilders are fully integrated into ModelBuilders.

# Registration

Registration is exactly the same as before, override the AddGeneratorUpdaters in the platform agnostic module and call the updaters.UseDetailViewLayoutBuilders() extension method.








 



 




using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Model.Core;

namespace MyApplication.Module
{
    public sealed partial class MyApplicationModule : ModuleBase
    {
        public override void AddGeneratorUpdaters(ModelNodesGeneratorUpdaters updaters)
        {
            base.AddGeneratorUpdaters(updaters);

            updaters.UseDetailViewLayoutBuilders();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Build the Layout

As with ModelBuilders this example will use fluent syntax combined with the WithDetailViewLayout.

The overload WithDetailViewLayout takes a signature of BuildLayoutFunctor which is a method that just returns a Layout object. The second overload provides a LayoutBuilder<T> obviating the need to create the builder independently.



























 
 





























































using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Layout;
using DevExpress.ExpressApp.Model.Core;
using DevExpress.Persistent.Base;

using MainDemo.Module.BusinessObjects;

using Xenial.Framework.ModelBuilders;
using Xenial.Framework.Layouts.Items.Base;

namespace MainDemo.Module
{
    public sealed partial class MyApplicationModule : ModuleBase
    {
        public override void AddGeneratorUpdaters(ModelNodesGeneratorUpdaters updaters)
        {
            base.AddGeneratorUpdaters(updaters);

            updaters.UseDetailViewLayoutBuilders();
        }

        public override void CustomizeTypesInfo(ITypesInfo typesInfo)
        {
            base.CustomizeTypesInfo(typesInfo);

            ModelBuilder.Create<Person>(typesInfo)
                .WithDetailViewLayout(b => new Layout
                {
                    b.HorizontalGroup(g =>
                    {
                        g.Caption = "Person";
                        g.ShowCaption = true;
                        g.RelativeSize = 25;
                    },
                        b.PropertyEditor(m => m.Image, editor =>
                        {
                            editor.ShowCaption = false;
                            editor.RelativeSize = 10;
                        }),
                        b.VerticalGroup(
                            b.PropertyEditor(m => m.FullName),
                            b.HorizontalGroup(
                                b.PropertyEditor(m => m.FirstName),
                                b.PropertyEditor(m => m.LastName)
                            ),
                            b.HorizontalGroup(
                                b.PropertyEditor(m => m.Email),
                                b.PropertyEditor(m => m.Phone)
                            ),
                            b.EmptySpaceItem()
                        )
                    ),
                    b.TabbedGroup(
                        b.Tab("Primary Address", FlowDirection.Horizontal,
                            b.VerticalGroup(
                                b.PropertyEditor(m => m.Address1.Street, e => e.CaptionLocation = Locations.Top),
                                b.HorizontalGroup(
                                    b.PropertyEditor(m => m.Address1.City, e => e.CaptionLocation = Locations.Top),
                                    b.PropertyEditor(m => m.Address1.ZipPostal, e => e.CaptionLocation = Locations.Top)
                                ),
                                b.PropertyEditor(m => m.Address1.StateProvince, e => e.CaptionLocation = Locations.Top),
                                b.PropertyEditor(m => m.Address1.Country, e => e.CaptionLocation = Locations.Top),
                                b.EmptySpaceItem()
                            ),
                            b.EmptySpaceItem()
                        ),
                        b.Tab("Secondary Address", FlowDirection.Horizontal,
                            b.VerticalGroup(
                                b.PropertyEditor(m => m.Address2.Street, e => e.CaptionLocation = Locations.Top),
                                b.HorizontalGroup(
                                    b.PropertyEditor(m => m.Address2.City, e => e.CaptionLocation = Locations.Top),
                                    b.PropertyEditor(m => m.Address2.ZipPostal, e => e.CaptionLocation = Locations.Top)
                                ),
                                b.PropertyEditor(m => m.Address2.StateProvince, e => e.CaptionLocation = Locations.Top),
                                b.PropertyEditor(m => m.Address2.Country, e => e.CaptionLocation = Locations.Top),
                                b.EmptySpaceItem()
                            ),
                            b.EmptySpaceItem()
                        ),
                        b.Tab("Additional Addresses",
                            b.PropertyEditor(m => m.Addresses)
                        )
                    )
                }).Build();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

As ModelBuilders are used to add the attribute to the Person class, there is no requirement to specify anything special:

using DevExpress.Persistent.Base;
using DevExpress.Xpo;

namespace MainDemo.Module.BusinessObjects
{
    [Persistent]
    [DefaultClassOptions]
    public class Person : XPObject
    {
        private string firstName;
        private string lastName;
        private string fullName;
        private string phone;
        private byte[] image;
        private string email;
        private Address address1;
        private Address address2;

        public Person(Session session) : base(session) { }

        public override void AfterConstruction()
        {
            base.AfterConstruction();
            Address1 = new Address(Session)
            {
                Person = this,
                Type = "Primary"
            };
            Address2 = new Address(Session)
            {
                Person = this,
                Type = "Secondary"
            };
        }

        [Persistent]
        public string FirstName
        {
            get => firstName;
            set => SetPropertyValue(nameof(FirstName), ref firstName, value);
        }

        [Persistent]
        public string LastName
        {
            get => lastName;
            set => SetPropertyValue(nameof(LastName), ref lastName, value);
        }

        [Persistent]
        public string FullName
        {
            get => fullName;
            set => SetPropertyValue(nameof(FullName), ref fullName, value);
        }

        [Persistent]
        public string Phone
        {
            get => phone;
            set => SetPropertyValue(nameof(Phone), ref phone, value);
        }

        [Persistent]
        public string Email
        {
            get => email;
            set => SetPropertyValue(nameof(Email), ref email, value);
        }

        [Persistent]
        public byte[] Image
        {
            get => image;
            set => SetPropertyValue(nameof(Image), ref image, value);
        }

        [Persistent]
        [ExpandObjectMembers(ExpandObjectMembers.InDetailView)]
        public Address Address1
        {
            get => address1;
            set => SetPropertyValue(nameof(Address1), ref address1, value);
        }

        [Persistent]
        [ExpandObjectMembers(ExpandObjectMembers.InDetailView)]
        public Address Address2
        {
            get => address2;
            set => SetPropertyValue(nameof(Address2), ref address2, value);
        }

        [Association("Person-Addresses")]
        [Aggregated]
        public XPCollection<Address> Addresses
        {
            get
            {
                return GetCollection<Address>(nameof(Addresses));
            }
        }
    }

    [Persistent]
    public class Address : XPObject
    {
        private Person person;
        private string type;
        private string street;
        private string city;
        private string stateProvince;
        private string zipPostal;
        private string country;

        public Address(Session session) : base(session) { }

        [Persistent]
        [Association("Person-Addresses")]
        public Person Person
        {
            get => person;
            set => SetPropertyValue(nameof(Person), ref person, value);
        }

        [Persistent]
        public string Type
        {
            get => type;
            set => SetPropertyValue(nameof(Type), ref type, value);
        }

        [Persistent]
        public string Street
        {
            get => street;
            set => SetPropertyValue(nameof(Street), ref street, value);
        }

        [Persistent]
        public string City
        {
            get => city;
            set => SetPropertyValue(nameof(City), ref city, value);
        }

        [Persistent]
        public string StateProvince
        {
            get => stateProvince;
            set => SetPropertyValue(nameof(StateProvince), ref stateProvince, value);
        }

        [Persistent]
        public string ZipPostal
        {
            get => zipPostal;
            set => SetPropertyValue(nameof(ZipPostal), ref zipPostal, value);
        }

        [Persistent]
        public string Country
        {
            get => country;
            set => SetPropertyValue(nameof(Country), ref country, value);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

TIP

This is the optimal way to add Layouts to classes to which source access is either unavailable or when it is desirable to keep the model clean from attributes.