Export (0) Print
Expand All

Using Data Annotations to Customize Data Classes

Silverlight

When you use data classes (also known as entity classes) in your Silverlight application, you can apply attributes to the class or members that specify validation rules, specify how the data is displayed, and set relationships between classes. The System.ComponentModel.DataAnnotations namespace contains the classes that are used as data attributes. By applying these attributes on the data class or member, you centralize the data definition and do not have to re-apply the same rules in multiple places.

The data annotation attributes fall into three categories: validation attributes, display attributes, and data modeling attributes. This topic describes these attributes and provides examples.

The System.ComponentModel.DataAnnotations namespace contains the following attributes which are used to enforce validation rules for data applied to the class or member:

Validation Attribute

Description

CustomValidationAttribute

Uses a custom method for validation.

DataTypeAttribute

Specifies a particular type of data, such as e-mail address or phone number.

EnumDataTypeAttribute

Ensures that the value exists in an enumeration.

RangeAttribute

Designates minimum and maximum constraints.

RegularExpressionAttribute

Uses a regular expression to determine valid values.

RequiredAttribute

Specifies that a value must be provided.

StringLengthAttribute

Designates maximum and minimum number of characters.

ValidationAttribute

Serves as base class for validation attributes.

All validation attributes derive from the ValidationAttribute class. The logic to determine if a value is valid is implemented in the overridden IsValid method. The Validate method calls the IsValid method and throws a ValidationException if the value is not valid.

To create customized validation checks, you can either create a class that derives from the ValidationAttribute class or create a method that performs the validation check and reference that method when applying the CustomValidationAttribute to the data member. When you create a class that derives from ValidationAttribute, override the IsValid method to provide the logic for your customized validation check.

Currently, the DataGrid control is the only control that automatically applies validation attributes. For an example of using a DataGrid control with a class that contains validation attributes, see the Data Grid Example below. When you do not use the DataGrid control, you must manually validate the values.

Manually Validating Values

When you do not use the DataGrid control to provide the interface for editing data, the validation attributes are not automatically applied. However, you can manually apply the validation test by using the Validator class. You can call the ValidateProperty method on the set accessor of a property to check the value against the validation attributes for the property. You must also set both ValidatesOnExceptions and NotifyOnValidationError properties to true when data binding to receive validation exceptions from validation attributes. For an example of manually applying validation, see the Data Binding Example below.

The System.ComponentModel.DataAnnotations namespace contains the following attributes which are used to specify how data from the class or member is displayed:

Display Attribute

Description

DataTypeAttribute

Specifies a particular type of data, such as e-mail address or phone number.

DisplayAttribute

Specifies localizable strings for data types and members that are used in the user interface.

DisplayColumnAttribute

Designates display and sorting properties when a table is used as a parent table in a foreign key relationship.

DisplayFormatAttribute

Specifies how data fields are displayed and formatted.

FilterUIHintAttribute

Designates the filtering behavior for a column.

UIHintAttribute

Designates the control and values to use to display the associated entity member.

The display attributes are automatically applied when used with the DataGrid control. You can manually retrieve display attribute values when data binding by using controls such as Label and DescriptionViewer. For an example of using the Label and DescriptionViewer controls with display attributes, see the Data Binding Example below.

The DataTypeAttribute attribute specifies a particular type for a data member and therefore is used as both a validation attribute and display attribute.

The System.ComponentModel.DataAnnotations namespace contains the following attributes which are used to specify the intended use of data members and the relationships between data classes:

Data Modeling Attribute

Description

AssociationAttribute

Specifies that an entity member represents a data relationship, such as a foreign key relationship.

ConcurrencyCheckAttribute

Designates that a property participates in optimistic concurrency checks.

EditableAttribute

Specifies whether users should be able to change the value of the entity property.

KeyAttribute

Specifies one or more entity properties to use as the unique identity for the entity.

TimestampAttribute

Designates a member as a time stamp value for data versioning.

This example shows a DataGrid control that enables the user to view and edit data from a data class. Data annotations are applied to the data class to specify display and validation behavior. The validation and display attributes are automatically applied when used with the DataGrid control.

The following example shows the data class named Product with data annotations applied to the members.


public class Product
{
    [Display(Name="Product Number")]
    [Range(0, 5000)]
    public int ProductID { get; set; }

    [Display(Name="Name")]
    [Required]
    public string ProductName { get; set; }

    [Display(Name="Price")]
    [DataType(DataType.Currency)]
    public double ListPrice { get; set; }

    [EnumDataType(typeof(ProductColor))]
    public ProductColor Color { get; set; }

    [Display(Name="Available")]
    public bool InStock { get; set; }

    public Product() { }

    public Product(int _productID, string _productName, 
        double _listPrice, ProductColor _color, bool _inStock)
    {
        this.ProductID = _productID;
        this.ProductName = _productName;
        this.ListPrice = _listPrice;
        this.Color = _color;
        this.InStock = _inStock;
    }
}

public enum ProductColor
{
    Red, White, Purple, Blue
}


The following examples show the page and code-behind file for displaying the data class in a data grid.


<Grid x:Name="LayoutRoot">
    <ScrollViewer x:Name="PageScrollViewer">
        <StackPanel x:Name="ContentStackPanel">
            <TextBlock x:Name="HeaderText" Text="Products"/>
            <sdk:DataGrid x:Name="DataGrid1" Foreground="Black" AutoGenerateColumns="True">
            </sdk:DataGrid>
        </StackPanel>
    </ScrollViewer>
</Grid>



public partial class ProductPage : Page
{
    ObservableCollection<Product> AvailableProducts;

    public ProductPage()
    {
        InitializeComponent();
        AvailableProducts = new ObservableCollection<Product>();
        AvailableProducts.Add(new Product(1, "Bike", 500, ProductColor.Red, true));
        AvailableProducts.Add(new Product(2, "Chair", 250, ProductColor.White, true));
        AvailableProducts.Add(new Product(3, "Plate", 20, ProductColor.Purple, false));
        AvailableProducts.Add(new Product(4, "Kite", 15, ProductColor.Blue, true));

        DataGrid1.ItemsSource = AvailableProducts;
    }
}


This example demonstrates a ValidationSummary control that displays errors for three TextBox controls on a form. The validation rules are specified in attributes in the Customer class and manually applied in the set accessor. The ValidatesOnExceptions and NotifyOnValidationError properties are set to true in the data binding.


<!-- NOTE: 
  By convention, the sdk prefix indicates a URI-based XAML namespace declaration 
  for Silverlight SDK client libraries. This namespace declaration is valid for 
  Silverlight 4 only. In Silverlight 3, you must use individual XAML namespace 
  declarations for each CLR assembly and namespace combination outside the scope 
  of the default Silverlight XAML namespace. For more information, see the help 
  topic "Prefixes and Mappings for Silverlight Libraries". 
-->
<UserControl x:Class="ValidationSample.MainPage"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"          
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
    <Grid x:Name="LayoutRoot" Margin="15" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="300"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="35"/>
            <RowDefinition Height="35"/>
            <RowDefinition Height="35"/>
            <RowDefinition Height="100"/>
        </Grid.RowDefinitions>
        <!-- Unbound Date of Birth field -->
        <sdk:Label Content="Date of Birth" IsRequired="True" Margin="5" />
        <StackPanel Orientation="Horizontal" Grid.Column="1">
            <sdk:DatePicker Height="23" />
            <sdk:DescriptionViewer Description="Please enter your date of birth."/>
        </StackPanel>

        <!-- ID Number field -->
        <sdk:Label Grid.Row="1" Margin="5" 
                         Target="{Binding ElementName=tbIdNumber}" />
        <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="1">
            <TextBox x:Name="tbIdNumber" Height="23" Width="100"
                     Text="{Binding IdNumber, Mode=TwoWay, 
                            ValidatesOnExceptions=true, NotifyOnValidationError=true}" />
            <sdk:DescriptionViewer Target="{Binding ElementName=tbIdNumber}"/>
        </StackPanel>
        <!-- Name field -->
        <sdk:Label Grid.Row="2" Margin="5" 
                         Target="{Binding ElementName=spName}"
                         PropertyPath="FirstName" />   
        <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="2">
            <StackPanel x:Name="spName" Orientation="Horizontal" >
              <TextBox x:Name="tbFirstName" Text="{Binding FirstName, Mode=TwoWay, 
                          ValidatesOnExceptions=true, NotifyOnValidationError=true}" 
                       Height="23" Width="100" />
              <TextBox x:Name="tbLastName" Text="{Binding LastName, Mode=TwoWay, 
                          ValidatesOnExceptions=true, NotifyOnValidationError=true}" 
                       Height="23" Width="100" />
              </StackPanel>
              <sdk:DescriptionViewer Target="{Binding ElementName=spName}"
                                           PropertyPath="FirstName"/>
        </StackPanel>

        <!-- ValidationSummary -->
        <sdk:ValidationSummary Grid.ColumnSpan="2" Grid.Row="3" />
    </Grid>
</UserControl>



using System.ComponentModel.DataAnnotations;
using System.Windows.Controls;

namespace ValidationSample
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            this.DataContext = new Customer("J", "Smith", 12345);
        }
    }

    public class Customer
    {
        // Private data members.
        private int m_IdNumber;
        private string m_FirstName;
        private string m_LastName;

        public Customer(string firstName, string lastName, int id)
        {
            this.IdNumber = id;
            this.FirstName = firstName;
            this.LastName = lastName;
        }

        // Public properties.
        [Display(Name = "ID Number", Description = "Enter an integer between 0 and 99999.")]
        [Range(0, 99999)]
        public int IdNumber
        {
            get { return m_IdNumber; }
            set
            {
                Validator.ValidateProperty(value, 
                    new ValidationContext(this, null, null) { MemberName = "IdNumber" });
                m_IdNumber = value;
            }
        }

        [Display(Name="Name", Description="First Name + Last Name.")]
        [Required(ErrorMessage = "First Name is required.")]
        [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = 
            "Numbers and special characters are not allowed in the name.")]
        public string FirstName
        {
            get { return m_FirstName; }

            set
            {
                Validator.ValidateProperty(value, 
                    new ValidationContext(this, null, null) { MemberName = "FirstName" });
                m_FirstName = value;
            }
        }

        [Required(ErrorMessage = "Last Name is required.")]
        [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = 
            "Numbers and special characters are not allowed in the name.")]
        [StringLength(8, MinimumLength = 3, ErrorMessage = 
            "Last name must be between 3 and 8 characters long.")]
        public string LastName
        {
            get { return m_LastName; }
            set
            {
                Validator.ValidateProperty(value, 
                    new ValidationContext(this, null, null) { MemberName = "LastName" });
                m_LastName = value;
            }
        }
    }
}


Community Additions

ADD
Show:
© 2014 Microsoft