# DetailViewLayoutBuilders - Introduction

DetailViewLayoutBuilders are a way of defining DetailViews in code. They are a domain specific language (DSL) to build Views in code rather than using the ModelEditor. As always in Xenial.Framework there are several ways to define them and to tell XAF when to consume them. They are an addition to the ModelEditor based approach, because they operate below the differences layer (opens new window).

DetailViewLayoutBuilders are one of the many NonVisual Components of Xenial.Framework designed around best practices and working efficiently in a team, however there are several benefits for smaller teams and projects as well.

# Installation

In your platform agnostic module (opens new window) install the Xenial.Framework (opens new window) package.

INFORMATION

By convention the platform agnostic module is usually named <Your Application>.Module. If you're unfamiliar with the Command Line Interface (cli) you can always use the Nuget package manager.

Whilst the Xenial.Framework can of course be used in platform specific modules, for the purposes of this documentation emphasis will be given to its use in the platform agnostic module of your project.

# Usage

Xenial.Framework provides both a simple and advanced registration pattern for DetailViewLayoutBuilders as well as one specially optimized for use within ModelBuilders.

All the DetailViewLayoutBuilder examples in this documentation will be based upon the simple 'Person' business object in the code below.

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

The standard default layout that would be produced by XAF is illustrated below;

Person Default Layout

The target layout that the code examples of LayoutBuilders in ensuing sections will aim to create is illustrated below;

Person Target Layout