# 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));
            }
        }
    }
}
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

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();
        }
    }
}
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

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));
            }
        }
    }
}
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

# 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));
            }
        }
    }
}
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

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();
        }
    }
}
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

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));
            }
        }
    }
}
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

# 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));
            }
        }
    }
}
1
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();
        }
    }
}
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