Data Annotation Attributes - Building Layout from Business Object
10 minutes to read
The Data Layout Control recognizes specific Data Annotation attributes applied to a bound business object’s properties. When building a layout, the Data Layout Control uses these attributes to give display names to layout items, specify the order of layout items, arrange items into groups and tabbed groups, specify the control’s readonly status, assign masks to editors, etc.
Note
To use Data Annotation attributes, ensure that the System.ComponentModel.DataAnnotations assembly is added to your project.
If your data source is a custom object decorated with attributes and this object is not an IEnumerable collection, do not pass it to the control’s DataLayoutControl.DataSource property directly. Instead, use the BindingSource component. Otherwise, data annotation attributes will not be parsed correctly.
Online Video
Consider the following MyClassTabsLayout business object, which contains multiple fields with no attributes applied. When this object is bound to a Data Layout Control, a linear layout is generated, as follows.
public class MyClassTabsLayout {
public string LastName { get; set; }
public string FirstName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public DateTime BirthDate { get; set; }
public GenderEnum Gender { get; set; }
public string Group { get; set; }
public DateTime HireDate { get; set; }
public decimal Salary { get; set; }
public string Title { get; set; }
public enum GenderEnum { Male, Female }
}
Public Class MyClassTabsLayout
Public Property LastName() As String
Public Property FirstName() As String
Public Property Phone() As String
Public Property Email() As String
Public Property AddressLine1() As String
Public Property AddressLine2() As String
Public Property BirthDate() As DateTime
Public Property Gender() As GenderEnum
Public Property Group() As String
Public Property HireDate() As DateTime
Public Property Salary() As Decimal
Public Property Title() As String
Public Enum GenderEnum
Male
Female
End Enum
End Class
To combine items in groups, specify item order, assign custom captions, set masks for editors, etc., certain Data Annotation attributes can be applied to the object’s fields.
In the following code, Data Annotation attributes are applied to fields of the same business object. The Data Layout Control takes into account these attributes when generating a layout.
using System.ComponentModel.DataAnnotations;
public class MyClassTabsLayout {
// The two items below will be displayed by DataLayoutControl
// in a borderless Name group without a title
[Display(GroupName = "<Name|>", Name = "Last name")]
public string LastName { get; set; }
[Display(GroupName = "<Name|>", Name = "First name", Order = 0)]
public string FirstName { get; set; }
//The four items below will go to a Contact tab within tabbed Tabs group.
[Display(GroupName = "{Tabs}/Contact", Order = 2), DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
[Display(GroupName = "{Tabs}/Contact", Order = 4), DataType(DataType.EmailAddress)]
public string Email { get; set; }
//The two items below will go to the Address group within the Contact tab.
[Display(GroupName = "{Tabs}/Contact/Address", ShortName = "")]
public string AddressLine1 { get; set; }
[Display(GroupName = "{Tabs}/Contact/Address", ShortName = "")]
public string AddressLine2 { get; set; }
//The two items below will go to a horizontally oriented Personal group.
[Display(GroupName = "Personal-", Name = "Birth date")]
public DateTime BirthDate { get; set; }
[Display(GroupName = "Personal-", Order = 3)]
public GenderEnum Gender { get; set; }
//The four items below will go to the Job tab of the tabbed Tabs group
[Display(GroupName = "{Tabs}/Job", Order = 6)]
public string Group { get; set; }
[Display(GroupName = "{Tabs}/Job", Name = "Hire date")]
public DateTime HireDate { get; set; }
[Display(GroupName = "{Tabs}/Job"), DataType(DataType.Currency)]
public decimal Salary { get; set; }
[Display(GroupName = "{Tabs}/Job", Order = 7)]
public string Title { get; set; }
public enum GenderEnum { Male, Female }
}
Public Class MyClassTabsLayout
' The two items below will be displayed by DataLayoutControl
' in a borderless Name group without a title
<Display(GroupName:="<Name|>", Name:="Last name")> _
Public Property LastName() As String
<Display(GroupName:="<Name|>", Name:="First name", Order:=0)> _
Public Property FirstName() As String
'The four items below will go to a Contact tab within tabbed Tabs group.
<Display(GroupName:="{Tabs}/Contact", Order:=2), DataType(DataType.PhoneNumber)> _
Public Property Phone() As String
<Display(GroupName:="{Tabs}/Contact", Order:=4), DataType(DataType.EmailAddress)> _
Public Property Email() As String
'The two items below will go to the Address group within the Contact tab.
<Display(GroupName:="{Tabs}/Contact/Address", ShortName:="")> _
Public Property AddressLine1() As String
<Display(GroupName:="{Tabs}/Contact/Address", ShortName:="")> _
Public Property AddressLine2() As String
'The two items below will go to horizontally oriented Personal group.
<Display(GroupName:="Personal-", Name:="Birth date")> _
Public Property BirthDate() As DateTime
<Display(GroupName:="Personal-", Order:=3)> _
Public Property Gender() As GenderEnum
'The four items below will go to the Job tab of the tabbed Tabs group
<Display(GroupName:="{Tabs}/Job", Order:=6)> _
Public Property Group() As String
<Display(GroupName:="{Tabs}/Job", Name:="Hire date")> _
Public Property HireDate() As DateTime
<Display(GroupName:="{Tabs}/Job"), DataType(DataType.Currency)> _
Public Property Salary() As Decimal
<Display(GroupName:="{Tabs}/Job", Order:=7)> _
Public Property Title() As String
Public Enum GenderEnum
Male
Female
End Enum
End Class
Layout Generation Attributes
The table below covers attributes that allow you to specify an item’s visibility, label, hint, read-only state and display format. Certain attributes are used to position items in regular and tabbed groups.
This parameter allows you to place a generated layout item into a group or tabbed group. If the parameter refers to a non-existing group, it will be automatically created.
Created Group Type
To specify the type of the created group, enclose the group name with the following characters.
[Display(GroupName = "[Name]")]
public string Notes { get; set; }
<Display(GroupName:="[Name]")> _
Public Property Notes() As String
Group Item Orientation
You can specify the orientation of items within the created group by appending “|” and “-“ characters to a group name. These specify the vertical and horizontal orientations of items respectively.
If the orientation is not specified using these characters, items are arranged vertically in this group. The orientation of items within the root group (the DataLayoutControl itself) is always vertical.
[Display(GroupName = "Personal-")]
public GenderEnum Gender { get; set; }
[Display(GroupName = "Personal-")]
public DateTime BirthDate { get; set; }
<Display(GroupName := "Personal-")> _
Public Property Gender() As GenderEnum
<Display(GroupName := "Personal-")> _
Public Property BirthDate() As DateTime
Nested Groups
To place a layout item into a group that is nested in another group, the GroupName parameter must specify the full path to the target group (including all parent groups). Group names should be delimited using the “/“ character in the full path.
[Display(GroupName = "{Tabs}/Job")]
public string Title { get; set; }
<Display(GroupName := "{Tabs}/Job")> _
Public Property Title() As String
Name
If specified, this parameter defines a label for the generated layout item. If the parameter is omitted, the layout item’s label is specified by the property’s name. You can set the parameter to an empty string to hide the layout item’s label.
[Display(Description = "Enter product amount")]
public int Quantity { get; set; }
<Display(Description := "Enter product amount")> _
Public Property Quantity() As Integer
Order
Specifies the order of the layout item among other layout items.
If this attribute parameter is omitted, the layout item is pushed to the bottom of its parent group.
[MetadataType(typeof(CompanyProductMetadata))]
public class Product {
public double UnitPrice { get; set; }
}
public class CompanyProductMetadata {
[ReadOnly(true)]
public double UnitPrice { get; set; }
}
<MetadataType(GetType(CompanyProductMetadata))>
Public Class Product
Public Property UnitPrice() As Double
End Class
Public Class CompanyProductMetadata
<[ReadOnly](True)>
Public Property UnitPrice() As Double
End Class
[DataType(DataType.Password), Display(Name = "New Password")]
public string NewPassword { get; set; }
[DataType(DataType.Password), Compare("NewPassword",
ErrorMessage="The new and confirmation passwords do not match"),
Display(Name="Confirm Password")]
public string ConfirmPassword { get; set; }
<DataType(DataType.Password), Display(Name := "New Password")>
Public Property NewPassword() As String
<DataType(DataType.Password), Compare("NewPassword",
ErrorMessage:="The new and confirmation passwords do not match"),
Display(Name:="Confirm Password")>
Public Property ConfirmPassword() As String