# ModelBuilders - Inline approach
This approach is very useful when applying just a couple of attributes to a business object being both quick and avoiding the requirement to create an additional (buddy)class.
# Class Level
The following code samples illustrate the use of inline ModelBuilders to replace Class Level attributes.
using System;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo;
namespace MainDemo.Module.BusinessObjects
{
[DefaultClassOptions]
[ModelDefault("Caption", "Task")]
public class DemoTask : BaseObject
{
public DemoTask(Session session) : base(session) { }
[ToolTip("View, assign or remove contacts for the current task")]
[Association("Contact-DemoTask")]
public XPCollection<Contact> Contacts
{
get
{
return GetCollection<Contact>(nameof(Contacts));
}
}
}
}
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
In order to replace the two class level attributes it is necessary to override the 'CustomTypesInfo' method (from within the Module.cs class located in the {application}Module agnostic project) utilizing the ModelBuilder.Create<T>()
method to create an inline 'ModelBuilder'.
TIP
The 'ModelBuilder' has a 'Build' method which must be called at the end in order to refresh the 'ITypesInfo' instance.
Before anything else import the correct namespace by adding the using Xenial.Framework.ModelBuilders;
statement to the top of the class.
With that done call the ModelBuilder
and use the provided built-in methods WithDefaultClassOptions
and HasCaption
to apply the attributes, followed by the required call to 'Build' as illustrated below.
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using Xenial.Framework;
using Xenial.Framework.ModelBuilders;
using MainDemo.Module.BusinessObjects;
namespace MyApplication.Module
{
public class MyApplicationModule : ModuleBase
{
public override void CustomizeTypesInfo(ITypesInfo typesInfo)
{
base.CustomizeTypesInfo(typesInfo);
ModelBuilder.Create<DemoTask>(typesInfo)
.WithDefaultClassOptions()
.HasCaption("Task")
.Build();
}
}
}
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
With that has been done the attributes themselves can be removed from the business object's code.
using System;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo;
namespace MainDemo.Module.BusinessObjects
{
// [DefaultClassOptions]
// [ModelDefault("Caption", "Task")]
public class DemoTask : BaseObject
{
public DemoTask(Session session) : base(session) { }
[ToolTip("View, assign or remove contacts for the current task")]
[Association("Contact-DemoTask")]
public XPCollection<Contact> Contacts
{
get
{
return GetCollection<Contact>(nameof(Contacts));
}
}
}
}
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
# Property Level
Property level attributes require a slightly different approach.
using System;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo;
namespace MainDemo.Module.BusinessObjects
{
[DefaultClassOptions]
[ModelDefault("Caption", "Task")]
public class DemoTask : BaseObject
{
public DemoTask(Session session) : base(session) { }
[ToolTip("View, assign or remove contacts for the current task")]
[Association("Contact-DemoTask")]
public XPCollection<Contact> Contacts
{
get
{
return GetCollection<Contact>(nameof(Contacts));
}
}
}
}
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
Once again the 'CustomizeTypesInfo' is overidden but in this instance the static ModelBuilder.Create<T>()
method is called to create an inline model builder. It returns an instance of a ModelBuilder
that can be used to apply property attributes as well. Use the builder.For(member => member.MemberName)
linq like syntax to provide a refactor and type safe way to specify the property of the business object for which the attribute is to be removed.
As before add a reference to the correct namespace by adding the using Xenial.Framework.ModelBuilders;
statement.
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using Xenial.Framework;
using Xenial.Framework.ModelBuilders;
using MainDemo.Module.BusinessObjects;
namespace MyApplication.Module
{
public class MyApplicationModule : ModuleBase
{
public override void CustomizeTypesInfo(ITypesInfo typesInfo)
{
base.CustomizeTypesInfo(typesInfo);
var builder = ModelBuilder.Create<DemoTask>(typesInfo);
builder.For(m => m.Contacts)
.HasTooltip("View, assign or remove contacts for the current task");
builder.Build();
}
}
}
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
Use the built in method HasTooltip
to apply the attribute to the business class property. Once done the attribute can be removed from the code.
using System;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo;
namespace MainDemo.Module.BusinessObjects
{
[DefaultClassOptions]
[ModelDefault("Caption", "Task")]
public class DemoTask : BaseObject
{
public DemoTask(Session session) : base(session) { }
// [ToolTip("View, assign or remove contacts for the current task")]
[Association("Contact-DemoTask")]
public XPCollection<Contact> Contacts
{
get
{
return GetCollection<Contact>(nameof(Contacts));
}
}
}
}
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
# Summary
The use of 'imperative' code over traditional attributes allows attributes to be applied to code which may be in a different assembly and potentially inaccesible, whilst retaining all the advantages proffered by C# to increase maintainability (string interpolation, etc).
On completion the business object's code will be as follows:
using System;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo;
namespace MainDemo.Module.BusinessObjects
{
public class DemoTask : BaseObject
{
public DemoTask(Session session) : base(session) { }
[Association("Contact-DemoTask")]
public XPCollection<Contact> Contacts
{
get
{
return GetCollection<Contact>(nameof(Contacts));
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using Xenial.Framework;
using Xenial.Framework.ModelBuilders;
using MainDemo.Module.BusinessObjects;
namespace MyApplication.Module
{
public class MyApplicationModule : ModuleBase
{
public override void CustomizeTypesInfo(ITypesInfo typesInfo)
{
base.CustomizeTypesInfo(typesInfo);
var builder = ModelBuilder.Create<DemoTask>(typesInfo)
.WithDefaultClassOptions()
.HasCaption("Task");
builder
.For(m => m.Contacts)
.HasTooltip("View, assign or remove contacts for the current task");
builder.Build();
}
}
}
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