# ListViewColumnBuilders - ColumnsBuilder<T> Syntax

The last section demonstrated that columns are essentially domain specific language which can, through the power of C#, produce in code, pixel perfect results which are both refactor safe and have a consistent look and feel.

Whilst the basic column building blocks can be verbose Xenial.Framework does provide a more robust and IntelliSense driven way to craft columns in code.

By way of a quick reminder the illustration below shows what the final layout should look like;

Person Target Columns

# Registration

As before the first task is to tell XAF to use the ListViewColumnBuilders.

Override the AddGeneratorUpdaters in the platform agnostic module and call the updaters.UseListViewColumnBuilders() 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.UseListViewColumnBuilders();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Defining the builder method

Once again declare a public static method in the business object class for which the layout is to be created called BuildColumns that returns a Xenial.Framework.Layouts.Columns instance and decorate the business object with the ListViewColumnsBuilderAttribute.

The ListViewColumnsBuilderAttribute defines the method and type that is responsible for building the ListView.










 


 
 
 
 



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

using Xenial.Framework.Layouts;

namespace MainDemo.Module.BusinessObjects
{
    [Persistent]
    [DefaultClassOptions]
    [ListViewColumnsBuilder]
    public class Person : XPObject
    {
        public static Columns BuildColumns()
        {
            return new Columns();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

After registering the builder and restarting the application (recall that XAF requires an application restart to register and apply changes to metadata) there is now an empty ListView because as yet there is no code within the ListViewColumnBuilders to construct the view.

Person Void Columns

TIP

There are some overloads for stricter registration patterns.

WARNING

If a blank page is not visible at this stage, make sure that the Model.DesignedDiffs.xafml files (also in the Win project) for this ListView have no differences and be sure to delete or disable the User differences file.

This file is usually located in the Application output directory called and named Model.User.xafml.

# Using the ColumnsBuilder<T> instance

At this stage the workflow moves from using the initializer syntax to hand craft the object graph to using the ColumnsBuilder<T> class as illustrated below;















 








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

using Xenial.Framework.Layouts;

namespace MainDemo.Module.BusinessObjects
{
    [Persistent]
    [DefaultClassOptions]
    [ListViewColumnsBuilder]
    public class Person : XPObject
    {
        public static Columns BuildColumns()
        {
            var b = new ColumnsBuilder<Person>();
            return new Columns
            {

            };
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

The column builder has a number of methods and overloads that accept some basic parameters like Caption and Width first, followed by a callback method Action<Column>.

These allow the use of a more compact syntax, without loosing any functionality over the traditional initializer syntax.

In the code sample below the parameters m and c are used, where m is short for Member and c for Column.
This convention is regarded as best practice but in reality any naming convention could be used.

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

namespace MainDemo.Module.BusinessObjects
{
    [Persistent]
    [DefaultClassOptions]
    [DetailViewLayoutBuilder]
    public class Person : XPObject
    {
        public static Columns BuildColumns()
        {
            var b = new ColumnsBuilder<Person>();

            return new Columns(new ListViewOptions
            {
                Caption = "All Persons",
                IsGroupPanelVisible = true,
                IsFooterVisible = true,
                ShowAutoFilterRow = true,
                ShowFindPanel = true,
                AutoExpandAllGroups = true
            })
            {
                b.Column(m => m.Address1.City, "Address", c =>
                {
                    c.Index = -1;
                    c.GroupIndex = 0;
                    c.SortOrder = ColumnSortOrder.Ascending;
                }),
                b.Column(m => m.FirstName, 70, c =>
                {
                    c.SortOrder = ColumnSortOrder.Ascending;
                }),
                b.Column(m => m.LastName, 70),
                b.Column(m => m.Phone, 30),
                b.Column(m => m.Email, 30)
            };
        }
    }
}
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

The benefit of this approach is that IntelliSense is available to guide the column building process obviating the need to remember all the type names, however it is a much denser syntax which may not be to all tastes.

TIP

It is perfectly acceptable to mix both initializer and functional style to suit personal preference or team guidelines.

# Inherit from ColumnsBuilder<T>

Thus far the ColumnsBuilder<T> has been used as an instance utilizing the convention based registration pattern for the builder.

By inheriting from ColumnsBuilder<T> and using the typed overload of the ListViewColumnsBuilderAttribute it is possible to reduce additional noise from the syntax. This is achieved by inheriting from the ColumnsBuilder<T> class and changing the registration as shown below.

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

namespace MainDemo.Module.BusinessObjects
{
    [Persistent]
    [DefaultClassOptions]
    [ListViewColumnsBuilder(typeof(PersonColumnsBuilder))]
    public class Person : XPObject {}

    public sealed class PersonColumnsBuilder : ColumnsBuilder<Person>
    {
        public Columns BuildLayout()
        {
            return new Columns(new ListViewOptions
            {
                Caption = "All Persons",
                IsGroupPanelVisible = true,
                IsFooterVisible = true,
                ShowAutoFilterRow = true,
                ShowFindPanel = true,
                AutoExpandAllGroups = true
            })
            {
                Column(m => m.Address1.City, "Address", c =>
                {
                    c.Index = -1;
                    c.GroupIndex = 0;
                    c.SortOrder = ColumnSortOrder.Ascending;
                }),
                Column(m => m.FirstName, 70, c =>
                {
                    c.SortOrder = ColumnSortOrder.Ascending;
                }),
                Column(m => m.LastName, 70),
                Column(m => m.Phone, 30),
                Column(m => m.Email, 30)
            };
        }
    }
}
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