windowsforms-114039-controls-and-libraries-form-layout-managers-layout-and-data-layout-controls-data-layout-control-data-annotation-attributes-building-layout-from-business-object.md
The Data Layout Control recognizes specific attributes from the System.ComponentModel.DataAnnotations namespace 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
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
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.
|
Attribute
|
Attribute’s Parameter
|
Description
| | --- | --- | --- | |
System.ComponentModel.DataAnnotations.DisplayAttribute
|
GroupName
|
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.
To specify the type of the created group, enclose the group name with the following characters.
<…> - Defines a borderless group that has no title (a LayoutControlGroup with the LayoutGroup.GroupBordersVisible property set to false ).
[…] - Defines a group with borders and a title (a LayoutControlGroup with the LayoutGroup.GroupBordersVisible property set to true ).
{…} - Defines a tabbed group (TabbedControlGroup).
[Display(GroupName = "[Name]")]
public string Notes { get; set; }
<Display(GroupName:="[Name]")> _
Public Property Notes() As String
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
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(Name = "Last name")]
public string LastName { get; set; }
<Display(Name := "Last name")> _
Public Property LastName() As String
| | |
ShortName
|
The same as the Name parameter.
| | |
Description
|
Assigns a tooltip to the generated layout item.
[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.
[Display(Order = 2)]
public GenderEnum Gender { get; set; }
[Display(Order = 1)]
public string Group { get; set; }
<Display(Order := 2)> _
Public Property Gender() As GenderEnum
<Display(Order := 1)> _
Public Property Group() As String
| | |
AutoGenerateField
|
Specifies whether or not a layout item (with a control) is automatically generated for the current field.
[Display(AutoGenerateField=false)]
public int ID{ get; set; }
<Display(AutoGenerateField := False)> _
Public Property ID() As Integer
| |
System.ComponentModel.ReadOnlyAttribute
|
|
Specifies whether this generated editor is in read-only mode.
[ReadOnly(true)]
public double UnitPrice { get; set; }
<[ReadOnly](True)>
Public Property UnitPrice() As Double
| |
System.ComponentModel.DataAnnotations.DisplayFormatAttribute
|
DataFormatString
|
Specifies the display format for the generated editor.
| | |
ApplyFormatInEditMode
|
Specifies whether the editor’s display format must also apply in edit mode.
[DisplayFormat(DataFormatString = "p", ApplyFormatInEditMode = true)]
public object SalesVsTarget { get; set; }
<DisplayFormat(DataFormatString := "p", ApplyFormatInEditMode := True)>
Public Property SalesVsTarget() As Object
|
The type of editors used to edit the bound object’s properties can be specified using the System.ComponentModel.DataAnnotations.DataTypeAttribute, System.ComponentModel.DataAnnotations.EnumDataTypeAttribute and System.ComponentModel.DataAnnotations.MetadataTypeAttribute.
|
|
Attribute parameter
|
Created editor
| | --- | --- | --- | | |
DataType.Date
|
[DataType(DataType.Date)]
public object HireDate { get; set; }
<DataType(DataType.Date))>
Public Property HireData() As Object
| | |
DataType.DateTime
|
| | |
DataType.Duration
|
| | |
DataType.Time
|
| | |
DataType.Text
|
| | |
DataType.MultilineText
|
| | |
DataType.Password
|
TextEdit with password input enabled
(see RepositoryItemTextEdit.UseSystemPasswordChar).
| | |
DataType.Url
|
| | |
DataType.Currency
|
TextEdit with the numeric currency mask (“c”).
| | |
DataType.Html
|
| |
| |
Description
| | --- | --- | --- | | | |
Allows you to replace numeric enumerator values with corresponding declarations.
[EnumDataType(typeof(ProductCategory))]
public int Category { get; set; }
public enum ProductCategory {
Beverages = 1,
Fruit = 2,
Vegetables = 3,
Meat = 4,
Condiments = 5,
Confections = 6,
DairyProducts = 7,
GrainsCereals = 8,
Seafood = 9
}
<EnumDataType(GetType(ProductCategory))>
Public Property Category() As Integer
Public Enum ProductCategory
Beverages = 1
Fruit = 2
Vegetables = 3
Meat = 4
Condiments = 5
Confections = 6
DairyProducts = 7
GrainsCereals = 8
Seafood = 9
End Enum
| |
| |
Description
| | --- | --- | --- | | | |
Allows you to derive data annotation attributes from another class.
[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
|
|
Attribute
|
Editor
| | --- | --- | |
System.ComponentModel.DataAnnotations.StringLengthAttribute
|
Specifies the maximum and minimum number of characters for string records within the editor.
[DataType(DataType.Password), StringLength(20, MinimumLength = 3)]
public string Password { get; set; }
<DataType(DataType.Password), StringLength(20, MinimumLength := 3)> _
Public Property Password() As String
| |
System.ComponentModel.DataAnnotations.RangeAttribute
|
A numeric value should lie in a specific range, set by using this attribute.
[DataType(DataType.Currency), Range(200, 5000)]
public int Currency { get; set; }
<DataType(DataType.Currency), Range(200, 5000)> _
Public Property Currency() As Integer
| |
System.ComponentModel.DataAnnotations.RequiredAttribute
|
Shows an error icon if an end-user is about to leave a modified editor when the edit value is null or an empty string.
[Required(AllowEmptyStrings=false)]
public string FirstName { get; set; }
<Required(AllowEmptyStrings := False)> _
Public Property FirstName() As String
| |
System.ComponentModel.DataAnnotations.CompareAttribute
|
Compares the editor’s value with another property. The entering of values that differ from the compared property’s value is restricted.
[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
|
See Also