# ListViewColumnBuilders - Record
Syntax
C#9 introduced a new record syntax (opens new window) which has been implemented within Xenial.Framework ColumnBuilders ensuring that columns can be built using with
expressions. Although not very different from initializers they make it possible to create a copy of a given record, which is particularly beneficial to a clean fluent syntax in combination with a functional style API.
# Setting the compiler options
Using this feature requires the compiler version to be set in the project. By default the framework will choose the compiler level based on the .NET version being used but it can be overridden by setting the LangVersion
(opens new window) property in the*.csproj
files.
By far the best way to use this feature is to create a Directory.Build.props
file in the same location as the application *.sln
file:
<Project>
<PropertyGroup>
<LangVersion>9.0</LangVersion>
<!--<LangVersion>latest</LangVersion> Alternative: just use the latest version, if you want the latest and greatest -->
</PropertyGroup>
</Project>
2
3
4
5
6
For more information on this topic please look at the Microsoft Documentation (opens new window)
TIP
To ensure that the compiler is picked up correctly close VisualStudio, delete all bin
and obj
folders and then restart VisualStudio
.
CAUTION
Whilst it is possible to use this in projects targeting .net frameworks below net5
(by adding a class called IsExternalInit
in the project) it is not officially supported by Microsoft:
#if !NET5
using System.ComponentModel;
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Reserved to be used by the compiler for tracking metadata.
/// This class should not be used by developers in source code.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit
{
}
}
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
WARNING
All code should be thoroughly tested after changing the compiler version.
Microsoft has done a great job trying not to break any existing client project, but because it is not supported on the old full framework (.NET4xx) officially, use this technique at your own risk.
# Registration
Registration is exactly the same as in the previous examples, 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
# Build the Columns
As this uses C#9 it is now possible to use the Target-typed new expressions feature
(opens new window) which removes a little bit of redundancy in the code as shown below:
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using Xenial.Framework.Layouts;
using Xenial.Framework.Layouts.Items;
using Xenial.Framework.Layouts.Items.Base;
using Xenial.Framework.Layouts.Items.LeafNodes;
namespace MainDemo.Module.BusinessObjects
{
[Persistent]
[DefaultClassOptions]
[ListViewColumnsBuilder]
public class Person : XPObject
{
private static ColumnsBuilder<Person> b = new();
public static Columns BuildColumns() => new(new()
{
Caption = "All Persons",
IsGroupPanelVisible = true,
IsFooterVisible = true,
ShowAutoFilterRow = true,
ShowFindPanel = true,
AutoExpandAllGroups = true
})
{
b.Column(m => m.Address1.City, "Address") with
{
Index = -1,
GroupIndex = 0,
SortOrder = ColumnSortOrder.Ascending
},
b.Column(m => m.FirstName, 70) with
{
SortOrder = ColumnSortOrder.Ascending
},
b.Column(m => m.LastName, 70),
b.Column(m => m.Phone, 30),
b.Column(m => m.Email, 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
The syntax is more concise than the initializer syntax and it is a little more structured. It's combining both the power of expression trees
to specify type safe layouts, as well as a familiar syntax comparable to initializers.
# A mixed sample
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using Xenial.Framework.Layouts;
using Xenial.Framework.Layouts.Items;
using Xenial.Framework.Layouts.Items.Base;
using Xenial.Framework.Layouts.Items.LeafNodes;
namespace MainDemo.Module.BusinessObjects
{
[Persistent]
[DefaultClassOptions]
[ListViewColumnsBuilder]
public class Person : XPObject
{
private static ColumnsBuilder<Person> b = new();
public static Columns BuildColumns() => new(new()
{
Caption = "All Persons",
IsGroupPanelVisible = true,
IsFooterVisible = true,
ShowAutoFilterRow = true,
ShowFindPanel = true,
AutoExpandAllGroups = true
})
{
b.Column(m => m.Address1.City, "Address") with
{
Index = -1,
GroupIndex = 0,
SortOrder = ColumnSortOrder.Ascending
},
b.Column(m => m.FirstName, 70, c =>
{
c.SortOrder = ColumnSortOrder.Ascending;
}),
new Column(nameof(LastName))
{
Width = 70
},
b.Column(m => m.Phone, 30),
b.Column(m => m.Email, 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
WARNING
Whilst this sample works without issue mixing syntax styles is not recommended. It may work from a technical standpoint but it adds complexity and harms readability.
Wherever possible coding styles and conventions should be clearly defined and adhered to.