# ListViewColumnBuilders - Simple Columns
As has been stated Xenial.Framework
is designed to be flexible and to minimize overheads. This is exemplified by the simple columns
approach of ListViewColumnBuilders
.
The first task is to tell XAF to use the ColumnBuilders
.
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();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Defining the builder method
With that done 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();
}
}
}
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.
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
.
# Building the columns
All the components used to build the columns are normal C# classes and have been designed to work well with C#'s initializer syntax as illustrated in the code below.
using DevExpress.Data;
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using Xenial.Framework.Layouts;
using Xenial.Framework.Layouts.ColumnItems;
namespace DXApplication6.Module.BusinessObjects
{
[Persistent]
[DefaultClassOptions]
[ListViewColumnsBuilder]
public class Person : XPObject
{
public static Columns BuildColumns()
{
return new Columns(new ListViewOptions()
{
Caption = "All Persons",
IsGroupPanelVisible = true,
IsFooterVisible = true,
ShowAutoFilterRow = true,
ShowFindPanel = true,
AutoExpandAllGroups = true
})
{
new Column($"{nameof(Address1)}.{nameof(Address.City)}")
{
Caption = "Address",
Index = -1,
GroupIndex = 0,
SortOrder = ColumnSortOrder.Ascending
},
new Column(nameof(FirstName))
{
SortOrder = ColumnSortOrder.Ascending,
Width = 70
},
new Column(nameof(LastName))
{
Width = 70
},
new Column(nameof(Phone))
{
Width = 30
},
new Column(nameof(Email))
{
Width = 30
},
};
}
}
}
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
This may appear to be a very verbose and long syntax pattern (Xenial.Framework does provide a more compact and advanced syntax patterns, see the reference for the used classes for more details) which will be examined in greater detail shortly.
Before that examination look at the result:
# Columns-Code-Review
The Columns
class is the container for the columns.
public static Columns BuildColumns()
{
return new Columns
{
/* ... */
}
}
2
3
4
5
6
7
TIP
From C#6 it has been possible to use Expression-bodied members (opens new window) to shorten the syntax to:
public static Columns BuildColumns() => new Columns {};
The basic building blocks for defining layouts are currently only the ListViewOptions
and Column
classes.
public static Columns BuildColumns()
{
return new Columns(
new ListViewOptions
{
/* ... */
}
)
{
new Column("PropertyName")
{
/* ... */
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TIP
There are several Column
properties that can be specified like Width
and SortOrder
, GroupIndex
, DisplayFormat
etc.
The Columns
class is a collection. So you can use initializer syntax, or use the default Add
method called by the initializer.
# Other registrations
If the convention based BuildColumns
is not suitable , there is the option to provide a custom method name by passing it as a parameter to the ListViewColumnsBuilderAttribute
.
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using Xenial.Framework.Layouts;
namespace MainDemo.Module.BusinessObjects
{
[Persistent]
[DefaultClassOptions]
[ListViewColumnsBuilder(nameof(BuildMyListViewColumns))]
public class Person : XPObject
{
public static Columns BuildMyListViewColumns()
{
return new Columns();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
TIP
The creation of columns in code can lead to large code files. Layout code can be moved to a separate file using the partial class
pattern (opens new window).
ListViewColumnBuilders
can be created in a separate class if, for example, there is a requirement to split XPO/XAF into separate assemblies, by providing the type of the class:
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using Xenial.Framework.Layouts;
namespace MainDemo.Module.BusinessObjects
{
[Persistent]
[DefaultClassOptions]
[ListViewColumnsBuilder(typeof(PersonColumnsBuilder), nameof(BuildMyListViewColumns))]
public class Person : XPObject { }
public static class PersonColumnsBuilder
{
public static Columns BuildMyListViewColumns()
{
return new Columns();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
TIP
The convention based naming approach also works for external types by just removing the target method name [ListViewColumnsBuilder(typeof(PersonColumns))]
.
Then of course the method name would be BuildColumns
in the PersonColumns
class.
# Declaring LookupListViews
Because LookupListViews are basically just ListViews that follow a specific naming convention Xenial.Framework provides a convenience attribute that has it's own convention by using the LookupListViewColumnBuilderAttribute
which expects an BuildLookupColumns
method, but otherwise follows the exact same semantics of the ListViewColumnsBuilderAttribute
.
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using Xenial.Framework.Layouts;
namespace MainDemo.Module.BusinessObjects
{
[Persistent]
[DefaultClassOptions]
[LookupListViewColumnsBuilder]
public class Person : XPObject
{
public static Columns BuildLookupColumns()
{
return new Columns();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18